diff --git a/.github/scripts/libraries_releases.main.kts b/.github/scripts/libraries_releases.main.kts index c47ef4fe386..422d5096db1 100755 --- a/.github/scripts/libraries_releases.main.kts +++ b/.github/scripts/libraries_releases.main.kts @@ -1,7 +1,9 @@ #!/usr/bin/env kotlin +// Copyright 2000-2025 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license. + /** - * This script is used to update the versions of libraries stored in the v-releases.list releases file. + * This script is used to update the versions of libraries stored in the v.list releases file. */ @file:DependsOn("org.jetbrains.kotlinx:kotlinx-serialization-json-jvm:1.7.0-RC") @@ -12,8 +14,7 @@ import kotlinx.serialization.json.jsonPrimitive import java.io.File import java.net.URL -val FILE_PATH = "v-releases.list" -val UNKNOWN = "unknown" +val FILE_PATH = "v.list" val releasesList = mapOf( "intellij-platform-gradle-plugin-version" to ReleaseInfo( @@ -47,11 +48,11 @@ val vars = releasesList.mapValues { (key, releaseInfo) -> val content = URL(releaseInfo.url).readText() Json.decodeFromString(content) .mapNotNull { it.jsonObject["name"] } - .map { it.jsonPrimitive.content.removePrefix("v") } + .map { it.jsonPrimitive.content.removePrefix("v").removePrefix("Version ") } .run(releaseInfo.transformer) } catch (e: Exception) { - println("Cannot resolve the latest $key version: ${e.message}") - UNKNOWN + println("Cannot resolve the latest '$key' version: ${e.message}") + throw e } } } @@ -59,15 +60,29 @@ val vars = releasesList.mapValues { (key, releaseInfo) -> "" } -""" - - +val newFileContent = StringBuilder() +val patternToInsertAfter = "" +val patternToSkipUntil = "" + +file(FILE_PATH).useLines { lines -> + var insideGeneratedContent = false + for (line in lines) { + if (line.trim() == patternToInsertAfter) { + insideGeneratedContent = true + newFileContent.appendLine(line) + newFileContent.appendLine(" ") + newFileContent.appendLine(" ") + newFileContent.appendLine(vars.joinToString(prefix = " ", separator = "\n ")) + } else if (line.trim() == patternToSkipUntil) { + insideGeneratedContent = false + newFileContent.appendLine(line) + } else if (!insideGeneratedContent) { + newFileContent.appendLine(line) + } + } +} - - ${vars.joinToString("\n ")} - -""".trimStart().let(file(FILE_PATH)::writeText) +file(FILE_PATH).writeText(newFileContent.toString()) fun file(path: String) = File(System.getenv("GITHUB_WORKSPACE") ?: "../../").resolve(path).also(File::createNewFile) diff --git a/.github/workflows/code-samples.yml b/.github/workflows/code-samples.yml index f58f337e65e..e274dddfa95 100644 --- a/.github/workflows/code-samples.yml +++ b/.github/workflows/code-samples.yml @@ -13,7 +13,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Fetch Sources - uses: actions/checkout@v4 + uses: actions/checkout@v5 samples: name: Code Samples / ${{ matrix.plugin }} @@ -24,6 +24,7 @@ jobs: matrix: plugin: - action_basics + - code_inspection_qodana/code_inspection - comparing_string_references_inspection - conditional_operator_intention - editor_basics @@ -43,9 +44,9 @@ jobs: - tree_structure_provider steps: - name: Fetch Sources - uses: actions/checkout@v4 + uses: actions/checkout@v5 - name: Setup Java - uses: actions/setup-java@v4 + uses: actions/setup-java@v5 with: distribution: zulu java-version: 17 @@ -60,6 +61,7 @@ jobs: shell: bash run: | echo "pluginVerifierHomeDir=~/.pluginVerifier" >> $GITHUB_OUTPUT + echo "sanitizedPluginName=$(echo '${{ matrix.plugin }}' | tr '/' '-')" >> $GITHUB_OUTPUT - name: Run Plugin Verifier run: | @@ -75,9 +77,9 @@ jobs: - name: Collect Plugin Verifier Result if: ${{ always() }} - uses: actions/upload-artifact@v4 + uses: actions/upload-artifact@v5 with: - name: ${{ matrix.plugin }}-pluginVerifier-result + name: ${{ steps.properties.outputs.sanitizedPluginName }}-pluginVerifier-result path: ${{ github.workspace }}/code_samples/${{ matrix.plugin }}/build/reports/pluginVerifier mirror: diff --git a/.github/workflows/dependabot-combine-prs.yml b/.github/workflows/dependabot-combine-prs.yml index bfbdc477461..1c62ae68d9f 100644 --- a/.github/workflows/dependabot-combine-prs.yml +++ b/.github/workflows/dependabot-combine-prs.yml @@ -31,7 +31,7 @@ jobs: # Steps represent a sequence of tasks that will be executed as part of the job steps: - - uses: actions/github-script@v7 + - uses: actions/github-script@v8 id: fetch-branch-names name: Fetch branch names with: @@ -99,7 +99,7 @@ jobs: console.log('Combined: ' + combined); return combined # Checks-out your repository under $GITHUB_WORKSPACE, so your job can access it - - uses: actions/checkout@v4 + - uses: actions/checkout@v5 with: fetch-depth: 0 # Creates a branch with other PR branches merged together @@ -125,7 +125,7 @@ jobs: git pull origin $sourcebranches --no-edit git push origin $COMBINE_BRANCH_NAME # Creates a PR with the new combined branch - - uses: actions/github-script@v7 + - uses: actions/github-script@v8 name: Create Combined Pull Request env: PRS_STRING: ${{ steps.fetch-branch-names.outputs.prs-string }} diff --git a/.github/workflows/generate-android-studio-releases.yml b/.github/workflows/generate-android-studio-releases.yml index c009f522ea5..02876be2465 100644 --- a/.github/workflows/generate-android-studio-releases.yml +++ b/.github/workflows/generate-android-studio-releases.yml @@ -9,7 +9,7 @@ jobs: generate: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v5 - name: Generate run: "${GITHUB_WORKSPACE}/.github/scripts/android_studio_releases.main.kts" - name: Commit changes diff --git a/.github/workflows/generate-descriptor-pages.yml b/.github/workflows/generate-descriptor-pages.yml index ecd931a5d0a..1ccabdfcc4d 100644 --- a/.github/workflows/generate-descriptor-pages.yml +++ b/.github/workflows/generate-descriptor-pages.yml @@ -10,7 +10,7 @@ jobs: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v5 - name: Generate descriptor pages content run: "${GITHUB_WORKSPACE}/.github/scripts/generate_descriptor_pages.main.kts" - name: Check for changes diff --git a/.github/workflows/generate-libraries-releases.yml b/.github/workflows/generate-libraries-releases.yml index 543f043beb4..310f5c6978e 100644 --- a/.github/workflows/generate-libraries-releases.yml +++ b/.github/workflows/generate-libraries-releases.yml @@ -9,11 +9,11 @@ jobs: generate: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v5 - name: Generate run: "${GITHUB_WORKSPACE}/.github/scripts/libraries_releases.main.kts" - name: Commit changes uses: Endbug/add-and-commit@v9 with: message: 'Generate Libraries releases variable file' - add: 'v-releases.list' + add: 'v.list' diff --git a/.github/workflows/verify-api-changes-pages.yml b/.github/workflows/verify-api-changes-pages.yml index dea8d19ade8..595a37511b1 100644 --- a/.github/workflows/verify-api-changes-pages.yml +++ b/.github/workflows/verify-api-changes-pages.yml @@ -13,9 +13,9 @@ jobs: runs-on: ubuntu-latest steps: - name: Fetch Sources - uses: actions/checkout@v4 + uses: actions/checkout@v5 - name: Setup Java - uses: actions/setup-java@v4 + uses: actions/setup-java@v5 with: distribution: zulu java-version: 11 diff --git a/.idea/compiler.xml b/.idea/compiler.xml index 55bc0a8b995..426ffbd418f 100644 --- a/.idea/compiler.xml +++ b/.idea/compiler.xml @@ -10,6 +10,8 @@ + + - \ No newline at end of file + diff --git a/.idea/gradle.xml b/.idea/gradle.xml index 96e6db21eaf..1f3037a3ae2 100644 --- a/.idea/gradle.xml +++ b/.idea/gradle.xml @@ -12,6 +12,21 @@ + + + + + + + + + + + + + + + @@ -101,11 +116,14 @@ + \ No newline at end of file diff --git a/.idea/inspectionProfiles/Project_Default.xml b/.idea/inspectionProfiles/Project_Default.xml index 0adc195759a..de089f218fe 100644 --- a/.idea/inspectionProfiles/Project_Default.xml +++ b/.idea/inspectionProfiles/Project_Default.xml @@ -10,4 +10,4 @@ - \ No newline at end of file + diff --git a/.idea/kotlinc.xml b/.idea/kotlinc.xml new file mode 100644 index 00000000000..125a7e07695 --- /dev/null +++ b/.idea/kotlinc.xml @@ -0,0 +1,6 @@ + + + + + diff --git a/.idea/modules/qodana-playground.main.iml b/.idea/modules/qodana-playground.main.iml new file mode 100644 index 00000000000..5fa2b624e6c --- /dev/null +++ b/.idea/modules/qodana-playground.main.iml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/code_samples/README.md b/code_samples/README.md index 7c91fddbd02..0f9c0a78e9e 100644 --- a/code_samples/README.md +++ b/code_samples/README.md @@ -37,9 +37,11 @@ In the following table, you may find all available samples provided in the separ | Code Sample | Description | |-----------------------------------------------------------------------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------| | [Action Basics](./action_basics) | Action and Action Group patterns implementation, adds entries to the Tools menu. | +| [Kotlin Class Name Convention Inspection](./code_inspection_qodana) | Local Inspection Tool, checks Kotlin class name convention. Allows to be run in Qodana | | [Comparing References Inspection](./comparing_string_references_inspection) | Local Inspection Tool, adds entries to **Settings | Editor | Inspections | Java | Probable Bugs**. | | [Conditional Operator Intention](./conditional_operator_intention) | Intention action, suggests converting a ternary operator into an `if` block and adds entry to **Settings | Editor | Intentions | SDK Intentions**. | | [Editor Basics](./editor_basics) | Basic Editor APIs example with editor popup menu with extra actions. | +| [Facet Basics](./facet_basics) | Custom Facet pattern, adds *SDK Facet* to the **Project Structure | Project Settings | Facets** menu. | | [Framework Basics](./framework_basics) | Basic *SDK Demo Framework* support added to the **File | New | Project | Java** wizard. | | [Live Templates](./live_templates) | Live templates for Markdown language, adds an entry to the **Settings | Editor | Live Templates** dialog. | | [Max Opened Projects](./max_opened_projects) | Application services and listeners, shows warning dialog when more than 3 open projects are opened. | diff --git a/code_samples/_gradleCompositeBuild/gradle.properties b/code_samples/_gradleCompositeBuild/gradle.properties new file mode 100644 index 00000000000..6904edb490e --- /dev/null +++ b/code_samples/_gradleCompositeBuild/gradle.properties @@ -0,0 +1,2 @@ +# Copyright 2000-2025 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license. +org.gradle.jvmargs=-Xmx1024m diff --git a/code_samples/_gradleCompositeBuild/settings.gradle.kts b/code_samples/_gradleCompositeBuild/settings.gradle.kts index 3006e85ab54..e193b9a5f11 100644 --- a/code_samples/_gradleCompositeBuild/settings.gradle.kts +++ b/code_samples/_gradleCompositeBuild/settings.gradle.kts @@ -5,6 +5,7 @@ rootProject.name = "SDK Code Samples" includeBuild("../action_basics") +includeBuild("../code_inspection_qodana") includeBuild("../comparing_string_references_inspection") includeBuild("../conditional_operator_intention") includeBuild("../editor_basics") diff --git a/code_samples/action_basics/build.gradle.kts b/code_samples/action_basics/build.gradle.kts index 538ebad0e64..c3fd371576b 100644 --- a/code_samples/action_basics/build.gradle.kts +++ b/code_samples/action_basics/build.gradle.kts @@ -1,8 +1,11 @@ // Copyright 2000-2025 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license. +import org.jetbrains.intellij.platform.gradle.IntelliJPlatformType.IntellijIdea +import org.jetbrains.intellij.platform.gradle.IntelliJPlatformType.IntellijIdeaCommunity +import org.jetbrains.intellij.platform.gradle.models.ProductRelease.Channel.RELEASE plugins { id("java") - id("org.jetbrains.intellij.platform") version "2.6.0" + id("org.jetbrains.intellij.platform") version "2.10.4" } group = "org.intellij.sdk" @@ -18,7 +21,7 @@ repositories { dependencies { intellijPlatform { - intellijIdeaCommunity("2024.2.6") + intellijIdea("2024.3.6") } } @@ -27,12 +30,21 @@ intellijPlatform { pluginConfiguration { ideaVersion { - sinceBuild = "242" + sinceBuild = "243" } } pluginVerification { ides { - recommended() + // since 253, IntelliJ IDEA Community and Ultimate have been merged into IntelliJ IDEA + select { + types = listOf(IntellijIdeaCommunity) + untilBuild = "252.*" + } + select { + types = listOf(IntellijIdea) + sinceBuild = "253" + channels = listOf(RELEASE) + } } } } diff --git a/code_samples/code_inspection_qodana/.gitattributes b/code_samples/code_inspection_qodana/.gitattributes new file mode 100644 index 00000000000..097f9f98d9e --- /dev/null +++ b/code_samples/code_inspection_qodana/.gitattributes @@ -0,0 +1,9 @@ +# +# https://help.github.com/articles/dealing-with-line-endings/ +# +# Linux start script should use lf +/gradlew text eol=lf + +# These are Windows script files and should use crlf +*.bat text eol=crlf + diff --git a/code_samples/code_inspection_qodana/.gitignore b/code_samples/code_inspection_qodana/.gitignore new file mode 100644 index 00000000000..1b6985c0094 --- /dev/null +++ b/code_samples/code_inspection_qodana/.gitignore @@ -0,0 +1,5 @@ +# Ignore Gradle project-specific cache directory +.gradle + +# Ignore Gradle build output directory +build diff --git a/code_samples/code_inspection_qodana/README.md b/code_samples/code_inspection_qodana/README.md new file mode 100644 index 00000000000..414f9364288 --- /dev/null +++ b/code_samples/code_inspection_qodana/README.md @@ -0,0 +1,44 @@ +# IntelliJ SDK Code Inspection Sample for Qodana + +**IntelliJ SDK Code Inspection Sample for Qodana** contains a code inspection sample for IntelliJ Platform plugins. + +A single rule is established: every class in the `service` packages must have a `Service` suffix. + +## Subprojects + +- `code_inspection` - a standalone IntelliJ Platform plugin with this inspection +- `qodana_playground` - a sample project which is validated by Qodana and the custom plugin + +## Building and Running + +1. Build the IntelliJ Platform plugin and copy it into the custom plugin directory in the Qodana playground project: + + ``` + ./gradlew stagePluginForQodana + ``` + + This will build a plugin JAR and copy it into the `qodana_playground/.qodana` directory. + +2. Run Qodana from the `qodana_playground` directory with the custom plugin installed. + + > This step requires installing [Qodana](https://www.jetbrains.com/help/qodana/quick-start.html#quickstart-run-using-cli) and [Docker](https://www.docker.com/get-started/) before running. + + ``` + cd qodana_playground + qodana scan --clear-cache -v $(echo $PWD/.qodana/*.jar):/opt/idea/custom-plugins/codeinspection.jar + ``` + +3. See the Qodana report in the browser. + +## Building and Running in the IDE + +1. Build the IntelliJ Platform plugin. + + ``` + ./gradlew buildPlugin + ``` + +2. Install the `build/code_inspection-.zip` plugin into JetBrains IDE manually. +3. Make sure that the Qodana plugin is installed and enabled in the JetBrains IDE. +4. Run the **Tools | Qodana | Try Code Analysis** action. +5. See the Qodana reports in the **Qodana** tool window in the IDE. diff --git a/code_samples/code_inspection_qodana/build.gradle.kts b/code_samples/code_inspection_qodana/build.gradle.kts new file mode 100644 index 00000000000..4588e27fb98 --- /dev/null +++ b/code_samples/code_inspection_qodana/build.gradle.kts @@ -0,0 +1,26 @@ +// Copyright 2000-2025 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license. + +val codeInspectionPlugin = "code_inspection" + +tasks.register("stagePluginForQodana") { + val qodanaDir = gradle.includedBuild("qodana_playground").projectDir.resolve(".qodana") + dependsOn(gradle.includedBuild(codeInspectionPlugin).task(":buildPlugin")) + from(gradle.includedBuild(codeInspectionPlugin) + .projectDir.resolve("build/libs")) + include("$codeInspectionPlugin-*.jar") + exclude("$codeInspectionPlugin-*-base.jar") + exclude("$codeInspectionPlugin-*-instrumented.jar") + exclude("$codeInspectionPlugin-*-searchableOptions.jar") + into(qodanaDir) +} + +tasks.register("buildPlugin") { + group = "build" + description = "Builds the Code Inspection plugin" + + val plugin = gradle.includedBuild(codeInspectionPlugin) + dependsOn(plugin.task(":buildPlugin")) + from(plugin.projectDir.resolve("build/distributions")) + include("$codeInspectionPlugin-*.zip") + into("build") +} diff --git a/code_samples/code_inspection_qodana/code_inspection/.gitignore b/code_samples/code_inspection_qodana/code_inspection/.gitignore new file mode 100644 index 00000000000..df6966a18f6 --- /dev/null +++ b/code_samples/code_inspection_qodana/code_inspection/.gitignore @@ -0,0 +1,7 @@ +.DS_Store +.gradle +.idea +.intellijPlatform +.kotlin +.qodana +build diff --git a/code_samples/code_inspection_qodana/code_inspection/.run/Run Plugin.run.xml b/code_samples/code_inspection_qodana/code_inspection/.run/Run Plugin.run.xml new file mode 100644 index 00000000000..9db62fb5e9a --- /dev/null +++ b/code_samples/code_inspection_qodana/code_inspection/.run/Run Plugin.run.xml @@ -0,0 +1,25 @@ + + + + + + + + false + true + false + false + + + \ No newline at end of file diff --git a/code_samples/code_inspection_qodana/code_inspection/CHANGELOG.md b/code_samples/code_inspection_qodana/code_inspection/CHANGELOG.md new file mode 100644 index 00000000000..6a3422c089e --- /dev/null +++ b/code_samples/code_inspection_qodana/code_inspection/CHANGELOG.md @@ -0,0 +1,9 @@ + + +# SDK: Comparing References Inspection Sample + +## [Unreleased] + +### Added + +- Initial release diff --git a/code_samples/code_inspection_qodana/code_inspection/build.gradle.kts b/code_samples/code_inspection_qodana/code_inspection/build.gradle.kts new file mode 100644 index 00000000000..3569d55c532 --- /dev/null +++ b/code_samples/code_inspection_qodana/code_inspection/build.gradle.kts @@ -0,0 +1,53 @@ +// Copyright 2000-2025 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license. +import org.jetbrains.intellij.platform.gradle.IntelliJPlatformType.IntellijIdea +import org.jetbrains.intellij.platform.gradle.IntelliJPlatformType.IntellijIdeaCommunity +import org.jetbrains.intellij.platform.gradle.models.ProductRelease.Channel.RELEASE + +plugins { + id("java") + id("org.jetbrains.kotlin.jvm") version "2.0.21" + id("org.jetbrains.intellij.platform") version "2.10.4" + id("org.jetbrains.qodana") version "2025.1.1" +} + +group = "org.intellij.sdk" +version = "2.0.0" + +repositories { + mavenCentral() + + intellijPlatform { + defaultRepositories() + } +} + +dependencies { + intellijPlatform { + intellijIdeaCommunity("2024.3.6") + bundledPlugin("org.jetbrains.kotlin") + } +} + +intellijPlatform { + buildSearchableOptions = false + + pluginConfiguration { + ideaVersion { + sinceBuild = "243" + } + } + pluginVerification { + ides { + // since 253, IntelliJ IDEA Community and Ultimate have been merged into IntelliJ IDEA + select { + types = listOf(IntellijIdeaCommunity) + untilBuild = "252.*" + } + select { + types = listOf(IntellijIdea) + sinceBuild = "253" + channels = listOf(RELEASE) + } + } + } +} diff --git a/code_samples/code_inspection_qodana/code_inspection/gradle.properties b/code_samples/code_inspection_qodana/code_inspection/gradle.properties new file mode 100644 index 00000000000..90ae95e8696 --- /dev/null +++ b/code_samples/code_inspection_qodana/code_inspection/gradle.properties @@ -0,0 +1,12 @@ +# Copyright 2000-2025 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license. + +# IntelliJ Platform Artifacts Repositories -> https://plugins.jetbrains.com/docs/intellij/intellij-artifacts.html + +# 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 diff --git a/code_samples/code_inspection_qodana/code_inspection/gradle/wrapper/gradle-wrapper.jar b/code_samples/code_inspection_qodana/code_inspection/gradle/wrapper/gradle-wrapper.jar new file mode 100644 index 00000000000..8bdaf60c75a Binary files /dev/null and b/code_samples/code_inspection_qodana/code_inspection/gradle/wrapper/gradle-wrapper.jar differ diff --git a/code_samples/code_inspection_qodana/code_inspection/gradle/wrapper/gradle-wrapper.properties b/code_samples/code_inspection_qodana/code_inspection/gradle/wrapper/gradle-wrapper.properties new file mode 100644 index 00000000000..2a84e188b85 --- /dev/null +++ b/code_samples/code_inspection_qodana/code_inspection/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,7 @@ +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-9.0.0-bin.zip +networkTimeout=10000 +validateDistributionUrl=true +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists diff --git a/code_samples/code_inspection_qodana/code_inspection/gradlew b/code_samples/code_inspection_qodana/code_inspection/gradlew new file mode 100755 index 00000000000..ef07e0162b1 --- /dev/null +++ b/code_samples/code_inspection_qodana/code_inspection/gradlew @@ -0,0 +1,251 @@ +#!/bin/sh + +# +# Copyright © 2015 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. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +# SPDX-License-Identifier: Apache-2.0 +# + +############################################################################## +# +# 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/platforms/jvm/plugins-application/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 +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 + +# This is normally unused +# shellcheck disable=SC2034 +APP_BASE_NAME=${0##*/} +# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036) +APP_HOME=$( cd -P "${APP_HOME:-./}" > /dev/null && printf '%s\n' "$PWD" ) || exit + +# Use the maximum available, or set MAX_FD != -1 to use that value. +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 ;; #( + MSYS* | MINGW* ) msys=true ;; #( + NONSTOP* ) nonstop=true ;; +esac + +CLASSPATH="\\\"\\\"" + + +# Determine the Java command to use to start the JVM. +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 + else + JAVACMD=$JAVA_HOME/bin/java + fi + if [ ! -x "$JAVACMD" ] ; then + die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." + fi +else + JAVACMD=java + if ! command -v java >/dev/null 2>&1 + then + 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 +location of your Java installation." + fi +fi + +# Increase the maximum file descriptors if we can. +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=SC2039,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=SC2039,SC3045 + ulimit -n "$MAX_FD" || + warn "Could not set maximum file descriptor limit to $MAX_FD" + esac +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" || "$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 + 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 + # 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 +fi + + +# 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"' + +# Collect all arguments for the java command: +# * DEFAULT_JVM_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments, +# and any embedded shellness will be escaped. +# * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be +# treated as '${Hostname}' itself on the command line. + +set -- \ + "-Dorg.gradle.appname=$APP_BASE_NAME" \ + -classpath "$CLASSPATH" \ + -jar "$APP_HOME/gradle/wrapper/gradle-wrapper.jar" \ + "$@" + +# 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. +# + +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/code_samples/code_inspection_qodana/code_inspection/gradlew.bat b/code_samples/code_inspection_qodana/code_inspection/gradlew.bat new file mode 100644 index 00000000000..db3a6ac207e --- /dev/null +++ b/code_samples/code_inspection_qodana/code_inspection/gradlew.bat @@ -0,0 +1,94 @@ +@rem +@rem Copyright 2015 the original author or authors. +@rem +@rem Licensed under the Apache License, Version 2.0 (the "License"); +@rem you may not use this file except in compliance with the License. +@rem You may obtain a copy of the License at +@rem +@rem https://www.apache.org/licenses/LICENSE-2.0 +@rem +@rem Unless required by applicable law or agreed to in writing, software +@rem distributed under the License is distributed on an "AS IS" BASIS, +@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +@rem See the License for the specific language governing permissions and +@rem limitations under the License. +@rem +@rem SPDX-License-Identifier: Apache-2.0 +@rem + +@if "%DEBUG%"=="" @echo off +@rem ########################################################################## +@rem +@rem Gradle startup script for Windows +@rem +@rem ########################################################################## + +@rem Set local scope for the variables with windows NT shell +if "%OS%"=="Windows_NT" setlocal + +set DIRNAME=%~dp0 +if "%DIRNAME%"=="" set DIRNAME=. +@rem This is normally unused +set APP_BASE_NAME=%~n0 +set APP_HOME=%DIRNAME% + +@rem Resolve any "." and ".." in APP_HOME to make it shorter. +for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi + +@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" + +@rem Find java.exe +if defined JAVA_HOME goto findJavaFromJavaHome + +set JAVA_EXE=java.exe +%JAVA_EXE% -version >NUL 2>&1 +if %ERRORLEVEL% equ 0 goto execute + +echo. 1>&2 +echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 1>&2 +echo. 1>&2 +echo Please set the JAVA_HOME variable in your environment to match the 1>&2 +echo location of your Java installation. 1>&2 + +goto fail + +:findJavaFromJavaHome +set JAVA_HOME=%JAVA_HOME:"=% +set JAVA_EXE=%JAVA_HOME%/bin/java.exe + +if exist "%JAVA_EXE%" goto execute + +echo. 1>&2 +echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 1>&2 +echo. 1>&2 +echo Please set the JAVA_HOME variable in your environment to match the 1>&2 +echo location of your Java installation. 1>&2 + +goto fail + +:execute +@rem Setup the command line + +set CLASSPATH= + + +@rem Execute Gradle +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" -jar "%APP_HOME%\gradle\wrapper\gradle-wrapper.jar" %* + +:end +@rem End local scope for the variables with windows NT shell +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! +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 + +:omega diff --git a/code_samples/code_inspection_qodana/code_inspection/qodana.yml b/code_samples/code_inspection_qodana/code_inspection/qodana.yml new file mode 100644 index 00000000000..81f13b9006e --- /dev/null +++ b/code_samples/code_inspection_qodana/code_inspection/qodana.yml @@ -0,0 +1,12 @@ +# Qodana configuration: +# https://www.jetbrains.com/help/qodana/qodana-yaml.html + +version: "1.0" +linter: jetbrains/qodana-jvm-community:2024.3 +projectJDK: "21" +profile: + name: qodana.recommended +exclude: + - name: All + paths: + - .qodana diff --git a/code_samples/code_inspection_qodana/code_inspection/settings.gradle.kts b/code_samples/code_inspection_qodana/code_inspection/settings.gradle.kts new file mode 100644 index 00000000000..f4457a7c10a --- /dev/null +++ b/code_samples/code_inspection_qodana/code_inspection/settings.gradle.kts @@ -0,0 +1,5 @@ +rootProject.name = "code_inspection" + +plugins { + id("org.gradle.toolchains.foojay-resolver-convention") version "1.0.0" +} diff --git a/code_samples/code_inspection_qodana/code_inspection/src/main/kotlin/org/intellij/sdk/codeInspection/ServicePackageClassNameInspection.kt b/code_samples/code_inspection_qodana/code_inspection/src/main/kotlin/org/intellij/sdk/codeInspection/ServicePackageClassNameInspection.kt new file mode 100644 index 00000000000..24f603b196d --- /dev/null +++ b/code_samples/code_inspection_qodana/code_inspection/src/main/kotlin/org/intellij/sdk/codeInspection/ServicePackageClassNameInspection.kt @@ -0,0 +1,35 @@ +// Copyright 2000-2025 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license. + +package org.intellij.sdk.codeInspection + +import com.intellij.codeInspection.ProblemHighlightType +import com.intellij.codeInspection.ProblemsHolder +import com.intellij.psi.PsiElementVisitor +import org.jetbrains.kotlin.idea.codeinsight.api.classic.inspections.AbstractKotlinInspection +import org.jetbrains.kotlin.psi.KtClass +import org.jetbrains.kotlin.psi.KtVisitorVoid + +class ServicePackageClassNameInspection : AbstractKotlinInspection() { + override fun buildVisitor( + holder: ProblemsHolder, + isOnTheFly: Boolean + ): PsiElementVisitor { + return object : KtVisitorVoid() { + override fun visitClass(klass: KtClass) { + val classNamePsi = klass.nameIdentifier ?: return + val classFqn = klass.fqName ?: return + if (klass.packageLastComponent == "service" && !classFqn.asString().endsWith("Service")) { + holder.registerProblem( + classNamePsi, + "Class name in the 'service' package must have a 'Service' suffix", + ProblemHighlightType.GENERIC_ERROR_OR_WARNING + ) + } + } + } + } + + private val KtClass.packageLastComponent: String + get() = containingKtFile.packageFqName.shortName().asString() + +} diff --git a/code_samples/code_inspection_qodana/code_inspection/src/main/resources/META-INF/plugin.xml b/code_samples/code_inspection_qodana/code_inspection/src/main/resources/META-INF/plugin.xml new file mode 100644 index 00000000000..9bbaa0b850e --- /dev/null +++ b/code_samples/code_inspection_qodana/code_inspection/src/main/resources/META-INF/plugin.xml @@ -0,0 +1,64 @@ + + + + + + org.intellij.sdk.classNameConventionCodeInspection + + + SDK: Class Name Convention Inspection + + + + IntelliJ SDK Code Inspection Sample for Qodana contains a code inspection sample + for IntelliJ Platform plugins.

+

A single rule is established: every class in the `service` packages must have a `Service` suffix.

+ ]]> +
+ + + IntelliJ Platform SDK + + + com.intellij.modules.platform + org.jetbrains.kotlin + + + + + + + + + + +
diff --git a/code_samples/code_inspection_qodana/code_inspection/src/main/resources/inspectionDescriptions/ServicePackageClassName.html b/code_samples/code_inspection_qodana/code_inspection/src/main/resources/inspectionDescriptions/ServicePackageClassName.html new file mode 100644 index 00000000000..3824624c564 --- /dev/null +++ b/code_samples/code_inspection_qodana/code_inspection/src/main/resources/inspectionDescriptions/ServicePackageClassName.html @@ -0,0 +1,12 @@ + + +Reports class names in the service packages that lack the Service suffix. +

Example:

+

+  package com.example.foo.service
+  class SomeComponent {
+    /* class members */
+  }
+
+ + diff --git a/code_samples/code_inspection_qodana/gradle/wrapper/gradle-wrapper.jar b/code_samples/code_inspection_qodana/gradle/wrapper/gradle-wrapper.jar new file mode 100644 index 00000000000..8bdaf60c75a Binary files /dev/null and b/code_samples/code_inspection_qodana/gradle/wrapper/gradle-wrapper.jar differ diff --git a/code_samples/code_inspection_qodana/gradle/wrapper/gradle-wrapper.properties b/code_samples/code_inspection_qodana/gradle/wrapper/gradle-wrapper.properties new file mode 100644 index 00000000000..2e1113280ef --- /dev/null +++ b/code_samples/code_inspection_qodana/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,7 @@ +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-9.1.0-bin.zip +networkTimeout=10000 +validateDistributionUrl=true +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists diff --git a/code_samples/code_inspection_qodana/gradlew b/code_samples/code_inspection_qodana/gradlew new file mode 100755 index 00000000000..adff685a034 --- /dev/null +++ b/code_samples/code_inspection_qodana/gradlew @@ -0,0 +1,248 @@ +#!/bin/sh + +# +# Copyright © 2015 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. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +# SPDX-License-Identifier: Apache-2.0 +# + +############################################################################## +# +# 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/platforms/jvm/plugins-application/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 +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 + +# This is normally unused +# shellcheck disable=SC2034 +APP_BASE_NAME=${0##*/} +# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036) +APP_HOME=$( cd -P "${APP_HOME:-./}" > /dev/null && printf '%s\n' "$PWD" ) || exit + +# Use the maximum available, or set MAX_FD != -1 to use that value. +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 ;; #( + MSYS* | MINGW* ) msys=true ;; #( + NONSTOP* ) nonstop=true ;; +esac + + + +# Determine the Java command to use to start the JVM. +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 + else + JAVACMD=$JAVA_HOME/bin/java + fi + if [ ! -x "$JAVACMD" ] ; then + die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." + fi +else + JAVACMD=java + if ! command -v java >/dev/null 2>&1 + then + 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 +location of your Java installation." + fi +fi + +# Increase the maximum file descriptors if we can. +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=SC2039,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=SC2039,SC3045 + ulimit -n "$MAX_FD" || + warn "Could not set maximum file descriptor limit to $MAX_FD" + esac +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" || "$msys" ; then + APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) + + JAVACMD=$( cygpath --unix "$JAVACMD" ) + + # Now convert the arguments - kludge to limit ourselves to /bin/sh + 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 + # 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 +fi + + +# 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"' + +# Collect all arguments for the java command: +# * DEFAULT_JVM_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments, +# and any embedded shellness will be escaped. +# * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be +# treated as '${Hostname}' itself on the command line. + +set -- \ + "-Dorg.gradle.appname=$APP_BASE_NAME" \ + -jar "$APP_HOME/gradle/wrapper/gradle-wrapper.jar" \ + "$@" + +# 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. +# + +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/code_samples/code_inspection_qodana/gradlew.bat b/code_samples/code_inspection_qodana/gradlew.bat new file mode 100644 index 00000000000..c4bdd3ab8e3 --- /dev/null +++ b/code_samples/code_inspection_qodana/gradlew.bat @@ -0,0 +1,93 @@ +@rem +@rem Copyright 2015 the original author or authors. +@rem +@rem Licensed under the Apache License, Version 2.0 (the "License"); +@rem you may not use this file except in compliance with the License. +@rem You may obtain a copy of the License at +@rem +@rem https://www.apache.org/licenses/LICENSE-2.0 +@rem +@rem Unless required by applicable law or agreed to in writing, software +@rem distributed under the License is distributed on an "AS IS" BASIS, +@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +@rem See the License for the specific language governing permissions and +@rem limitations under the License. +@rem +@rem SPDX-License-Identifier: Apache-2.0 +@rem + +@if "%DEBUG%"=="" @echo off +@rem ########################################################################## +@rem +@rem Gradle startup script for Windows +@rem +@rem ########################################################################## + +@rem Set local scope for the variables with windows NT shell +if "%OS%"=="Windows_NT" setlocal + +set DIRNAME=%~dp0 +if "%DIRNAME%"=="" set DIRNAME=. +@rem This is normally unused +set APP_BASE_NAME=%~n0 +set APP_HOME=%DIRNAME% + +@rem Resolve any "." and ".." in APP_HOME to make it shorter. +for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi + +@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" + +@rem Find java.exe +if defined JAVA_HOME goto findJavaFromJavaHome + +set JAVA_EXE=java.exe +%JAVA_EXE% -version >NUL 2>&1 +if %ERRORLEVEL% equ 0 goto execute + +echo. 1>&2 +echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 1>&2 +echo. 1>&2 +echo Please set the JAVA_HOME variable in your environment to match the 1>&2 +echo location of your Java installation. 1>&2 + +goto fail + +:findJavaFromJavaHome +set JAVA_HOME=%JAVA_HOME:"=% +set JAVA_EXE=%JAVA_HOME%/bin/java.exe + +if exist "%JAVA_EXE%" goto execute + +echo. 1>&2 +echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 1>&2 +echo. 1>&2 +echo Please set the JAVA_HOME variable in your environment to match the 1>&2 +echo location of your Java installation. 1>&2 + +goto fail + +:execute +@rem Setup the command line + + + +@rem Execute Gradle +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -jar "%APP_HOME%\gradle\wrapper\gradle-wrapper.jar" %* + +:end +@rem End local scope for the variables with windows NT shell +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! +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 + +:omega diff --git a/code_samples/code_inspection_qodana/qodana_playground/.gitignore b/code_samples/code_inspection_qodana/qodana_playground/.gitignore new file mode 100644 index 00000000000..8b029849af7 --- /dev/null +++ b/code_samples/code_inspection_qodana/qodana_playground/.gitignore @@ -0,0 +1,5 @@ +.DS_Store +.gradle +.idea +.qodana +build diff --git a/code_samples/code_inspection_qodana/qodana_playground/build.gradle.kts b/code_samples/code_inspection_qodana/qodana_playground/build.gradle.kts new file mode 100644 index 00000000000..6526e92c4c3 --- /dev/null +++ b/code_samples/code_inspection_qodana/qodana_playground/build.gradle.kts @@ -0,0 +1,24 @@ +// Copyright 2000-2025 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license. + +plugins { + kotlin("jvm") version "2.2.0" +} + +group = "org.intellij.sdk" +version = "1.0-SNAPSHOT" + +repositories { + mavenCentral() +} + +dependencies { + testImplementation(kotlin("test")) +} + +tasks.test { + useJUnitPlatform() +} + +kotlin { + jvmToolchain(17) +} diff --git a/code_samples/code_inspection_qodana/qodana_playground/gradle/wrapper/gradle-wrapper.jar b/code_samples/code_inspection_qodana/qodana_playground/gradle/wrapper/gradle-wrapper.jar new file mode 100644 index 00000000000..1b33c55baab Binary files /dev/null and b/code_samples/code_inspection_qodana/qodana_playground/gradle/wrapper/gradle-wrapper.jar differ diff --git a/code_samples/code_inspection_qodana/qodana_playground/gradle/wrapper/gradle-wrapper.properties b/code_samples/code_inspection_qodana/qodana_playground/gradle/wrapper/gradle-wrapper.properties new file mode 100644 index 00000000000..838c72605aa --- /dev/null +++ b/code_samples/code_inspection_qodana/qodana_playground/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,8 @@ +# Copyright 2000-2025 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license. +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-8.14-bin.zip +networkTimeout=10000 +validateDistributionUrl=true +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists diff --git a/code_samples/code_inspection_qodana/qodana_playground/gradlew b/code_samples/code_inspection_qodana/qodana_playground/gradlew new file mode 100755 index 00000000000..23d15a93670 --- /dev/null +++ b/code_samples/code_inspection_qodana/qodana_playground/gradlew @@ -0,0 +1,251 @@ +#!/bin/sh + +# +# 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. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +# SPDX-License-Identifier: Apache-2.0 +# + +############################################################################## +# +# 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/platforms/jvm/plugins-application/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 +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 + +# This is normally unused +# shellcheck disable=SC2034 +APP_BASE_NAME=${0##*/} +# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036) +APP_HOME=$( cd -P "${APP_HOME:-./}" > /dev/null && printf '%s\n' "$PWD" ) || exit + +# Use the maximum available, or set MAX_FD != -1 to use that value. +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 ;; #( + MSYS* | MINGW* ) msys=true ;; #( + NONSTOP* ) nonstop=true ;; +esac + +CLASSPATH="\\\"\\\"" + + +# Determine the Java command to use to start the JVM. +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 + else + JAVACMD=$JAVA_HOME/bin/java + fi + if [ ! -x "$JAVACMD" ] ; then + die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." + fi +else + JAVACMD=java + if ! command -v java >/dev/null 2>&1 + then + 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 +location of your Java installation." + fi +fi + +# Increase the maximum file descriptors if we can. +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=SC2039,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=SC2039,SC3045 + ulimit -n "$MAX_FD" || + warn "Could not set maximum file descriptor limit to $MAX_FD" + esac +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" || "$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 + 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 + # 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 +fi + + +# 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"' + +# Collect all arguments for the java command: +# * DEFAULT_JVM_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments, +# and any embedded shellness will be escaped. +# * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be +# treated as '${Hostname}' itself on the command line. + +set -- \ + "-Dorg.gradle.appname=$APP_BASE_NAME" \ + -classpath "$CLASSPATH" \ + -jar "$APP_HOME/gradle/wrapper/gradle-wrapper.jar" \ + "$@" + +# 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. +# + +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/code_samples/code_inspection_qodana/qodana_playground/gradlew.bat b/code_samples/code_inspection_qodana/qodana_playground/gradlew.bat new file mode 100644 index 00000000000..db3a6ac207e --- /dev/null +++ b/code_samples/code_inspection_qodana/qodana_playground/gradlew.bat @@ -0,0 +1,94 @@ +@rem +@rem Copyright 2015 the original author or authors. +@rem +@rem Licensed under the Apache License, Version 2.0 (the "License"); +@rem you may not use this file except in compliance with the License. +@rem You may obtain a copy of the License at +@rem +@rem https://www.apache.org/licenses/LICENSE-2.0 +@rem +@rem Unless required by applicable law or agreed to in writing, software +@rem distributed under the License is distributed on an "AS IS" BASIS, +@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +@rem See the License for the specific language governing permissions and +@rem limitations under the License. +@rem +@rem SPDX-License-Identifier: Apache-2.0 +@rem + +@if "%DEBUG%"=="" @echo off +@rem ########################################################################## +@rem +@rem Gradle startup script for Windows +@rem +@rem ########################################################################## + +@rem Set local scope for the variables with windows NT shell +if "%OS%"=="Windows_NT" setlocal + +set DIRNAME=%~dp0 +if "%DIRNAME%"=="" set DIRNAME=. +@rem This is normally unused +set APP_BASE_NAME=%~n0 +set APP_HOME=%DIRNAME% + +@rem Resolve any "." and ".." in APP_HOME to make it shorter. +for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi + +@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" + +@rem Find java.exe +if defined JAVA_HOME goto findJavaFromJavaHome + +set JAVA_EXE=java.exe +%JAVA_EXE% -version >NUL 2>&1 +if %ERRORLEVEL% equ 0 goto execute + +echo. 1>&2 +echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 1>&2 +echo. 1>&2 +echo Please set the JAVA_HOME variable in your environment to match the 1>&2 +echo location of your Java installation. 1>&2 + +goto fail + +:findJavaFromJavaHome +set JAVA_HOME=%JAVA_HOME:"=% +set JAVA_EXE=%JAVA_HOME%/bin/java.exe + +if exist "%JAVA_EXE%" goto execute + +echo. 1>&2 +echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 1>&2 +echo. 1>&2 +echo Please set the JAVA_HOME variable in your environment to match the 1>&2 +echo location of your Java installation. 1>&2 + +goto fail + +:execute +@rem Setup the command line + +set CLASSPATH= + + +@rem Execute Gradle +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" -jar "%APP_HOME%\gradle\wrapper\gradle-wrapper.jar" %* + +:end +@rem End local scope for the variables with windows NT shell +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! +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 + +:omega diff --git a/code_samples/code_inspection_qodana/qodana_playground/qodana.yaml b/code_samples/code_inspection_qodana/qodana_playground/qodana.yaml new file mode 100644 index 00000000000..518bef86d93 --- /dev/null +++ b/code_samples/code_inspection_qodana/qodana_playground/qodana.yaml @@ -0,0 +1,7 @@ +version: "1.0" +linter: qodana-jvm-community +projectJDK: "21" +profile: + name: qodana.recommended +include: + - name: org.intellij.sdk.codeInspection.ServicePackageClassNameInspection diff --git a/code_samples/code_inspection_qodana/qodana_playground/settings.gradle.kts b/code_samples/code_inspection_qodana/qodana_playground/settings.gradle.kts new file mode 100644 index 00000000000..bfb140d0d56 --- /dev/null +++ b/code_samples/code_inspection_qodana/qodana_playground/settings.gradle.kts @@ -0,0 +1,7 @@ +// Copyright 2000-2025 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license. + +rootProject.name = "qodana_playground" + +plugins { + id("org.gradle.toolchains.foojay-resolver-convention").version("1.0.0") +} diff --git a/code_samples/code_inspection_qodana/qodana_playground/src/main/kotlin/org/intellij/sdk/qodana/Runner.kt b/code_samples/code_inspection_qodana/qodana_playground/src/main/kotlin/org/intellij/sdk/qodana/Runner.kt new file mode 100644 index 00000000000..c1de69b87aa --- /dev/null +++ b/code_samples/code_inspection_qodana/qodana_playground/src/main/kotlin/org/intellij/sdk/qodana/Runner.kt @@ -0,0 +1,12 @@ +// Copyright 2000-2025 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license. + +package org.intellij.sdk.qodana + +import org.intellij.sdk.qodana.service.AnotherComponent +import org.intellij.sdk.qodana.service.Component +import kotlin.collections.forEach + +fun main() { + val components = listOf(Component(), AnotherComponent()) + components.forEach { println(it) } +} diff --git a/code_samples/code_inspection_qodana/qodana_playground/src/main/kotlin/org/intellij/sdk/qodana/service/AnotherComponent.kt b/code_samples/code_inspection_qodana/qodana_playground/src/main/kotlin/org/intellij/sdk/qodana/service/AnotherComponent.kt new file mode 100644 index 00000000000..7b96dbce84f --- /dev/null +++ b/code_samples/code_inspection_qodana/qodana_playground/src/main/kotlin/org/intellij/sdk/qodana/service/AnotherComponent.kt @@ -0,0 +1,7 @@ +// Copyright 2000-2025 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license. + +package org.intellij.sdk.qodana.service + +class AnotherComponent { + override fun toString() = "AnotherComponent" +} diff --git a/code_samples/code_inspection_qodana/qodana_playground/src/main/kotlin/org/intellij/sdk/qodana/service/Component.kt b/code_samples/code_inspection_qodana/qodana_playground/src/main/kotlin/org/intellij/sdk/qodana/service/Component.kt new file mode 100644 index 00000000000..ae63e585f17 --- /dev/null +++ b/code_samples/code_inspection_qodana/qodana_playground/src/main/kotlin/org/intellij/sdk/qodana/service/Component.kt @@ -0,0 +1,7 @@ +// Copyright 2000-2025 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license. + +package org.intellij.sdk.qodana.service + +class Component { + override fun toString() = "Component" +} diff --git a/code_samples/code_inspection_qodana/settings.gradle.kts b/code_samples/code_inspection_qodana/settings.gradle.kts new file mode 100644 index 00000000000..d0dba7544b9 --- /dev/null +++ b/code_samples/code_inspection_qodana/settings.gradle.kts @@ -0,0 +1,6 @@ +// Copyright 2000-2025 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license. + +rootProject.name = "code_inspection_qodana" + +includeBuild("../code_inspection_qodana/code_inspection") +includeBuild("../code_inspection_qodana/qodana_playground") diff --git a/code_samples/comparing_string_references_inspection/build.gradle.kts b/code_samples/comparing_string_references_inspection/build.gradle.kts index 1f7d0d72810..cb363ed6302 100644 --- a/code_samples/comparing_string_references_inspection/build.gradle.kts +++ b/code_samples/comparing_string_references_inspection/build.gradle.kts @@ -1,9 +1,12 @@ // Copyright 2000-2025 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license. +import org.jetbrains.intellij.platform.gradle.IntelliJPlatformType.IntellijIdea +import org.jetbrains.intellij.platform.gradle.IntelliJPlatformType.IntellijIdeaCommunity import org.jetbrains.intellij.platform.gradle.TestFrameworkType +import org.jetbrains.intellij.platform.gradle.models.ProductRelease.Channel.RELEASE plugins { id("java") - id("org.jetbrains.intellij.platform") version "2.6.0" + id("org.jetbrains.intellij.platform") version "2.10.4" } group = "org.intellij.sdk" @@ -19,7 +22,7 @@ repositories { dependencies { intellijPlatform { - intellijIdeaCommunity("2024.2.6") + intellijIdea("2024.3.6") bundledPlugin("com.intellij.java") testFramework(TestFrameworkType.Plugin.Java) @@ -36,12 +39,21 @@ intellijPlatform { pluginConfiguration { ideaVersion { - sinceBuild = "242" + sinceBuild = "243" } } pluginVerification { ides { - recommended() + // since 253, IntelliJ IDEA Community and Ultimate have been merged into IntelliJ IDEA + select { + types = listOf(IntellijIdeaCommunity) + untilBuild = "252.*" + } + select { + types = listOf(IntellijIdea) + sinceBuild = "253" + channels = listOf(RELEASE) + } } } } diff --git a/code_samples/conditional_operator_intention/build.gradle.kts b/code_samples/conditional_operator_intention/build.gradle.kts index ad626f353b1..89d47977e75 100644 --- a/code_samples/conditional_operator_intention/build.gradle.kts +++ b/code_samples/conditional_operator_intention/build.gradle.kts @@ -1,9 +1,12 @@ // Copyright 2000-2025 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license. +import org.jetbrains.intellij.platform.gradle.IntelliJPlatformType.IntellijIdea +import org.jetbrains.intellij.platform.gradle.IntelliJPlatformType.IntellijIdeaCommunity import org.jetbrains.intellij.platform.gradle.TestFrameworkType +import org.jetbrains.intellij.platform.gradle.models.ProductRelease.Channel.RELEASE plugins { id("java") - id("org.jetbrains.intellij.platform") version "2.6.0" + id("org.jetbrains.intellij.platform") version "2.10.4" } group = "org.intellij.sdk" @@ -19,7 +22,7 @@ repositories { dependencies { intellijPlatform { - intellijIdeaCommunity("2024.2.6") + intellijIdea("2024.3.6") bundledPlugin("com.intellij.java") testFramework(TestFrameworkType.Plugin.Java) @@ -36,12 +39,21 @@ intellijPlatform { pluginConfiguration { ideaVersion { - sinceBuild = "242" + sinceBuild = "243" } } pluginVerification { ides { - recommended() + // since 253, IntelliJ IDEA Community and Ultimate have been merged into IntelliJ IDEA + select { + types = listOf(IntellijIdeaCommunity) + untilBuild = "252.*" + } + select { + types = listOf(IntellijIdea) + sinceBuild = "253" + channels = listOf(RELEASE) + } } } } diff --git a/code_samples/editor_basics/build.gradle.kts b/code_samples/editor_basics/build.gradle.kts index 538ebad0e64..c3fd371576b 100644 --- a/code_samples/editor_basics/build.gradle.kts +++ b/code_samples/editor_basics/build.gradle.kts @@ -1,8 +1,11 @@ // Copyright 2000-2025 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license. +import org.jetbrains.intellij.platform.gradle.IntelliJPlatformType.IntellijIdea +import org.jetbrains.intellij.platform.gradle.IntelliJPlatformType.IntellijIdeaCommunity +import org.jetbrains.intellij.platform.gradle.models.ProductRelease.Channel.RELEASE plugins { id("java") - id("org.jetbrains.intellij.platform") version "2.6.0" + id("org.jetbrains.intellij.platform") version "2.10.4" } group = "org.intellij.sdk" @@ -18,7 +21,7 @@ repositories { dependencies { intellijPlatform { - intellijIdeaCommunity("2024.2.6") + intellijIdea("2024.3.6") } } @@ -27,12 +30,21 @@ intellijPlatform { pluginConfiguration { ideaVersion { - sinceBuild = "242" + sinceBuild = "243" } } pluginVerification { ides { - recommended() + // since 253, IntelliJ IDEA Community and Ultimate have been merged into IntelliJ IDEA + select { + types = listOf(IntellijIdeaCommunity) + untilBuild = "252.*" + } + select { + types = listOf(IntellijIdea) + sinceBuild = "253" + channels = listOf(RELEASE) + } } } } diff --git a/code_samples/editor_basics/src/main/java/org/intellij/sdk/editor/EditorAreaIllustration.java b/code_samples/editor_basics/src/main/java/org/intellij/sdk/editor/EditorAreaIllustration.java index a118b4c03ac..db8bcdc6ccb 100644 --- a/code_samples/editor_basics/src/main/java/org/intellij/sdk/editor/EditorAreaIllustration.java +++ b/code_samples/editor_basics/src/main/java/org/intellij/sdk/editor/EditorAreaIllustration.java @@ -1,4 +1,4 @@ -// Copyright 2000-2023 JetBrains s.r.o. and other contributors. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. +// Copyright 2000-2025 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license. package org.intellij.sdk.editor; @@ -29,9 +29,10 @@ public class EditorAreaIllustration extends AnAction { @Override public void actionPerformed(@NotNull final AnActionEvent e) { // Get access to the editor and caret model. update() validated editor's existence. - final Editor editor = e.getRequiredData(CommonDataKeys.EDITOR); + final Editor editor = e.getData(CommonDataKeys.EDITOR); + if (editor == null) return; final CaretModel caretModel = editor.getCaretModel(); - // Getting the primary caret ensures we get the correct one of a possible many. + // Getting the primary caret ensures we get the correct one of possible many. final Caret primaryCaret = caretModel.getPrimaryCaret(); // Get the caret information LogicalPosition logicalPos = primaryCaret.getLogicalPosition(); @@ -57,7 +58,7 @@ public void update(@NotNull final AnActionEvent e) { // Get required data keys final Project project = e.getProject(); final Editor editor = e.getData(CommonDataKeys.EDITOR); - // Set visibility only in case of existing project and editor + // Set visibility only in the case of an existing project and editor e.getPresentation().setEnabledAndVisible(project != null && editor != null); } diff --git a/code_samples/editor_basics/src/main/java/org/intellij/sdk/editor/EditorHandlerIllustration.java b/code_samples/editor_basics/src/main/java/org/intellij/sdk/editor/EditorHandlerIllustration.java index 67cd1e09189..52df5627fa8 100644 --- a/code_samples/editor_basics/src/main/java/org/intellij/sdk/editor/EditorHandlerIllustration.java +++ b/code_samples/editor_basics/src/main/java/org/intellij/sdk/editor/EditorHandlerIllustration.java @@ -1,4 +1,4 @@ -// Copyright 2000-2023 JetBrains s.r.o. and other contributors. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. +// Copyright 2000-2025 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license. package org.intellij.sdk.editor; @@ -27,8 +27,9 @@ public class EditorHandlerIllustration extends AnAction { @Override public void actionPerformed(@NotNull final AnActionEvent e) { // Editor is known to exist from update, so it's not null - final Editor editor = e.getRequiredData(CommonDataKeys.EDITOR); - // Get the action manager in order to get the necessary action handler... + final Editor editor = e.getData(CommonDataKeys.EDITOR); + if (editor == null) return; + // Get the action manager to get the necessary action handler... final EditorActionManager actionManager = EditorActionManager.getInstance(); // Get the action handler registered to clone carets final EditorActionHandler actionHandler = @@ -38,7 +39,7 @@ public void actionPerformed(@NotNull final AnActionEvent e) { } /** - * Enables and sets visibility of this action menu item if: + * Enables and sets the visibility of this action menu item if: *
    *
  • a project is open
  • *
  • an editor is active
  • diff --git a/code_samples/editor_basics/src/main/java/org/intellij/sdk/editor/EditorIllustrationAction.java b/code_samples/editor_basics/src/main/java/org/intellij/sdk/editor/EditorIllustrationAction.java index d13be66a7d5..d64146cca05 100644 --- a/code_samples/editor_basics/src/main/java/org/intellij/sdk/editor/EditorIllustrationAction.java +++ b/code_samples/editor_basics/src/main/java/org/intellij/sdk/editor/EditorIllustrationAction.java @@ -1,4 +1,4 @@ -// Copyright 2000-2023 JetBrains s.r.o. and other contributors. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. +// Copyright 2000-2025 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license. package org.intellij.sdk.editor; @@ -24,7 +24,7 @@ public class EditorIllustrationAction extends AnAction { } /** - * Replaces the run of text selected by the primary caret with a fixed string. + * Replaces a text selected by the primary caret with a fixed string. * * @param e Event related to this action */ @@ -32,8 +32,10 @@ public class EditorIllustrationAction extends AnAction { public void actionPerformed(@NotNull final AnActionEvent e) { // Get all the required data from data keys // Editor and Project were verified in update(), so they are not null. - final Editor editor = e.getRequiredData(CommonDataKeys.EDITOR); - final Project project = e.getRequiredData(CommonDataKeys.PROJECT); + final Editor editor = e.getData(CommonDataKeys.EDITOR); + if (editor == null) return; + final Project project = e.getData(CommonDataKeys.PROJECT); + if (project == null) return; final Document document = editor.getDocument(); // Work off of the primary caret to get the selection info Caret primaryCaret = editor.getCaretModel().getPrimaryCaret(); @@ -63,7 +65,7 @@ public void update(@NotNull final AnActionEvent e) { // Get required data keys final Project project = e.getProject(); final Editor editor = e.getData(CommonDataKeys.EDITOR); - // Set visibility and enable only in case of existing project and editor and if a selection exists + // Set visibility and enable only in case of an existing project and editor and if a selection exists e.getPresentation().setEnabledAndVisible( project != null && editor != null && editor.getSelectionModel().hasSelection() ); diff --git a/code_samples/facet_basics/build.gradle.kts b/code_samples/facet_basics/build.gradle.kts index 538ebad0e64..c3fd371576b 100644 --- a/code_samples/facet_basics/build.gradle.kts +++ b/code_samples/facet_basics/build.gradle.kts @@ -1,8 +1,11 @@ // Copyright 2000-2025 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license. +import org.jetbrains.intellij.platform.gradle.IntelliJPlatformType.IntellijIdea +import org.jetbrains.intellij.platform.gradle.IntelliJPlatformType.IntellijIdeaCommunity +import org.jetbrains.intellij.platform.gradle.models.ProductRelease.Channel.RELEASE plugins { id("java") - id("org.jetbrains.intellij.platform") version "2.6.0" + id("org.jetbrains.intellij.platform") version "2.10.4" } group = "org.intellij.sdk" @@ -18,7 +21,7 @@ repositories { dependencies { intellijPlatform { - intellijIdeaCommunity("2024.2.6") + intellijIdea("2024.3.6") } } @@ -27,12 +30,21 @@ intellijPlatform { pluginConfiguration { ideaVersion { - sinceBuild = "242" + sinceBuild = "243" } } pluginVerification { ides { - recommended() + // since 253, IntelliJ IDEA Community and Ultimate have been merged into IntelliJ IDEA + select { + types = listOf(IntellijIdeaCommunity) + untilBuild = "252.*" + } + select { + types = listOf(IntellijIdea) + sinceBuild = "253" + channels = listOf(RELEASE) + } } } } diff --git a/code_samples/framework_basics/build.gradle.kts b/code_samples/framework_basics/build.gradle.kts index ab7166e7fe9..6fd4612b6a9 100644 --- a/code_samples/framework_basics/build.gradle.kts +++ b/code_samples/framework_basics/build.gradle.kts @@ -1,8 +1,11 @@ // Copyright 2000-2025 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license. +import org.jetbrains.intellij.platform.gradle.IntelliJPlatformType.IntellijIdea +import org.jetbrains.intellij.platform.gradle.IntelliJPlatformType.IntellijIdeaCommunity +import org.jetbrains.intellij.platform.gradle.models.ProductRelease.Channel.RELEASE plugins { id("java") - id("org.jetbrains.intellij.platform") version "2.6.0" + id("org.jetbrains.intellij.platform") version "2.10.4" } group = "org.intellij.sdk" @@ -18,7 +21,7 @@ repositories { dependencies { intellijPlatform { - intellijIdeaCommunity("2024.2.6") + intellijIdea("2024.3.6") bundledPlugin("com.intellij.java") } } @@ -28,12 +31,21 @@ intellijPlatform { pluginConfiguration { ideaVersion { - sinceBuild = "242" + sinceBuild = "243" } } pluginVerification { ides { - recommended() + // since 253, IntelliJ IDEA Community and Ultimate have been merged into IntelliJ IDEA + select { + types = listOf(IntellijIdeaCommunity) + untilBuild = "252.*" + } + select { + types = listOf(IntellijIdea) + sinceBuild = "253" + channels = listOf(RELEASE) + } } } } diff --git a/code_samples/live_templates/build.gradle.kts b/code_samples/live_templates/build.gradle.kts index 538ebad0e64..c3fd371576b 100644 --- a/code_samples/live_templates/build.gradle.kts +++ b/code_samples/live_templates/build.gradle.kts @@ -1,8 +1,11 @@ // Copyright 2000-2025 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license. +import org.jetbrains.intellij.platform.gradle.IntelliJPlatformType.IntellijIdea +import org.jetbrains.intellij.platform.gradle.IntelliJPlatformType.IntellijIdeaCommunity +import org.jetbrains.intellij.platform.gradle.models.ProductRelease.Channel.RELEASE plugins { id("java") - id("org.jetbrains.intellij.platform") version "2.6.0" + id("org.jetbrains.intellij.platform") version "2.10.4" } group = "org.intellij.sdk" @@ -18,7 +21,7 @@ repositories { dependencies { intellijPlatform { - intellijIdeaCommunity("2024.2.6") + intellijIdea("2024.3.6") } } @@ -27,12 +30,21 @@ intellijPlatform { pluginConfiguration { ideaVersion { - sinceBuild = "242" + sinceBuild = "243" } } pluginVerification { ides { - recommended() + // since 253, IntelliJ IDEA Community and Ultimate have been merged into IntelliJ IDEA + select { + types = listOf(IntellijIdeaCommunity) + untilBuild = "252.*" + } + select { + types = listOf(IntellijIdea) + sinceBuild = "253" + channels = listOf(RELEASE) + } } } } diff --git a/code_samples/max_opened_projects/build.gradle.kts b/code_samples/max_opened_projects/build.gradle.kts index 237e2bb7400..b73e0b9f72d 100644 --- a/code_samples/max_opened_projects/build.gradle.kts +++ b/code_samples/max_opened_projects/build.gradle.kts @@ -1,9 +1,12 @@ // Copyright 2000-2025 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license. +import org.jetbrains.intellij.platform.gradle.IntelliJPlatformType.IntellijIdea +import org.jetbrains.intellij.platform.gradle.IntelliJPlatformType.IntellijIdeaCommunity +import org.jetbrains.intellij.platform.gradle.models.ProductRelease.Channel.RELEASE plugins { id("java") - id("org.jetbrains.kotlin.jvm") version "1.9.25" - id("org.jetbrains.intellij.platform") version "2.6.0" + id("org.jetbrains.kotlin.jvm") version "2.0.21" + id("org.jetbrains.intellij.platform") version "2.10.4" } group = "org.intellij.sdk" @@ -19,7 +22,7 @@ repositories { dependencies { intellijPlatform { - intellijIdeaCommunity("2024.2.6") + intellijIdea("2024.3.6") } } @@ -28,12 +31,21 @@ intellijPlatform { pluginConfiguration { ideaVersion { - sinceBuild = "242" + sinceBuild = "243" } } pluginVerification { ides { - recommended() + // since 253, IntelliJ IDEA Community and Ultimate have been merged into IntelliJ IDEA + select { + types = listOf(IntellijIdeaCommunity) + untilBuild = "252.*" + } + select { + types = listOf(IntellijIdea) + sinceBuild = "253" + channels = listOf(RELEASE) + } } } } diff --git a/code_samples/module/build.gradle.kts b/code_samples/module/build.gradle.kts index 538ebad0e64..c3fd371576b 100644 --- a/code_samples/module/build.gradle.kts +++ b/code_samples/module/build.gradle.kts @@ -1,8 +1,11 @@ // Copyright 2000-2025 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license. +import org.jetbrains.intellij.platform.gradle.IntelliJPlatformType.IntellijIdea +import org.jetbrains.intellij.platform.gradle.IntelliJPlatformType.IntellijIdeaCommunity +import org.jetbrains.intellij.platform.gradle.models.ProductRelease.Channel.RELEASE plugins { id("java") - id("org.jetbrains.intellij.platform") version "2.6.0" + id("org.jetbrains.intellij.platform") version "2.10.4" } group = "org.intellij.sdk" @@ -18,7 +21,7 @@ repositories { dependencies { intellijPlatform { - intellijIdeaCommunity("2024.2.6") + intellijIdea("2024.3.6") } } @@ -27,12 +30,21 @@ intellijPlatform { pluginConfiguration { ideaVersion { - sinceBuild = "242" + sinceBuild = "243" } } pluginVerification { ides { - recommended() + // since 253, IntelliJ IDEA Community and Ultimate have been merged into IntelliJ IDEA + select { + types = listOf(IntellijIdeaCommunity) + untilBuild = "252.*" + } + select { + types = listOf(IntellijIdea) + sinceBuild = "253" + channels = listOf(RELEASE) + } } } } diff --git a/code_samples/project_model/build.gradle.kts b/code_samples/project_model/build.gradle.kts index ab7166e7fe9..6fd4612b6a9 100644 --- a/code_samples/project_model/build.gradle.kts +++ b/code_samples/project_model/build.gradle.kts @@ -1,8 +1,11 @@ // Copyright 2000-2025 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license. +import org.jetbrains.intellij.platform.gradle.IntelliJPlatformType.IntellijIdea +import org.jetbrains.intellij.platform.gradle.IntelliJPlatformType.IntellijIdeaCommunity +import org.jetbrains.intellij.platform.gradle.models.ProductRelease.Channel.RELEASE plugins { id("java") - id("org.jetbrains.intellij.platform") version "2.6.0" + id("org.jetbrains.intellij.platform") version "2.10.4" } group = "org.intellij.sdk" @@ -18,7 +21,7 @@ repositories { dependencies { intellijPlatform { - intellijIdeaCommunity("2024.2.6") + intellijIdea("2024.3.6") bundledPlugin("com.intellij.java") } } @@ -28,12 +31,21 @@ intellijPlatform { pluginConfiguration { ideaVersion { - sinceBuild = "242" + sinceBuild = "243" } } pluginVerification { ides { - recommended() + // since 253, IntelliJ IDEA Community and Ultimate have been merged into IntelliJ IDEA + select { + types = listOf(IntellijIdeaCommunity) + untilBuild = "252.*" + } + select { + types = listOf(IntellijIdea) + sinceBuild = "253" + channels = listOf(RELEASE) + } } } } diff --git a/code_samples/project_view_pane/build.gradle.kts b/code_samples/project_view_pane/build.gradle.kts index 6517f74e100..c3fd371576b 100644 --- a/code_samples/project_view_pane/build.gradle.kts +++ b/code_samples/project_view_pane/build.gradle.kts @@ -1,8 +1,11 @@ // Copyright 2000-2025 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license. +import org.jetbrains.intellij.platform.gradle.IntelliJPlatformType.IntellijIdea +import org.jetbrains.intellij.platform.gradle.IntelliJPlatformType.IntellijIdeaCommunity +import org.jetbrains.intellij.platform.gradle.models.ProductRelease.Channel.RELEASE plugins { id("java") - id("org.jetbrains.intellij.platform") version "2.6.0" + id("org.jetbrains.intellij.platform") version "2.10.4" } group = "org.intellij.sdk" @@ -18,7 +21,7 @@ repositories { dependencies { intellijPlatform { - intellijIdeaCommunity("2024.2.6") + intellijIdea("2024.3.6") } } @@ -27,13 +30,21 @@ intellijPlatform { pluginConfiguration { ideaVersion { - sinceBuild = "242" + sinceBuild = "243" } } pluginVerification { ides { - recommended() + // since 253, IntelliJ IDEA Community and Ultimate have been merged into IntelliJ IDEA + select { + types = listOf(IntellijIdeaCommunity) + untilBuild = "252.*" + } + select { + types = listOf(IntellijIdea) + sinceBuild = "253" + channels = listOf(RELEASE) + } } } } - diff --git a/code_samples/project_wizard/build.gradle.kts b/code_samples/project_wizard/build.gradle.kts index 538ebad0e64..c3fd371576b 100644 --- a/code_samples/project_wizard/build.gradle.kts +++ b/code_samples/project_wizard/build.gradle.kts @@ -1,8 +1,11 @@ // Copyright 2000-2025 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license. +import org.jetbrains.intellij.platform.gradle.IntelliJPlatformType.IntellijIdea +import org.jetbrains.intellij.platform.gradle.IntelliJPlatformType.IntellijIdeaCommunity +import org.jetbrains.intellij.platform.gradle.models.ProductRelease.Channel.RELEASE plugins { id("java") - id("org.jetbrains.intellij.platform") version "2.6.0" + id("org.jetbrains.intellij.platform") version "2.10.4" } group = "org.intellij.sdk" @@ -18,7 +21,7 @@ repositories { dependencies { intellijPlatform { - intellijIdeaCommunity("2024.2.6") + intellijIdea("2024.3.6") } } @@ -27,12 +30,21 @@ intellijPlatform { pluginConfiguration { ideaVersion { - sinceBuild = "242" + sinceBuild = "243" } } pluginVerification { ides { - recommended() + // since 253, IntelliJ IDEA Community and Ultimate have been merged into IntelliJ IDEA + select { + types = listOf(IntellijIdeaCommunity) + untilBuild = "252.*" + } + select { + types = listOf(IntellijIdea) + sinceBuild = "253" + channels = listOf(RELEASE) + } } } } diff --git a/code_samples/psi_demo/build.gradle.kts b/code_samples/psi_demo/build.gradle.kts index ab7166e7fe9..6fd4612b6a9 100644 --- a/code_samples/psi_demo/build.gradle.kts +++ b/code_samples/psi_demo/build.gradle.kts @@ -1,8 +1,11 @@ // Copyright 2000-2025 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license. +import org.jetbrains.intellij.platform.gradle.IntelliJPlatformType.IntellijIdea +import org.jetbrains.intellij.platform.gradle.IntelliJPlatformType.IntellijIdeaCommunity +import org.jetbrains.intellij.platform.gradle.models.ProductRelease.Channel.RELEASE plugins { id("java") - id("org.jetbrains.intellij.platform") version "2.6.0" + id("org.jetbrains.intellij.platform") version "2.10.4" } group = "org.intellij.sdk" @@ -18,7 +21,7 @@ repositories { dependencies { intellijPlatform { - intellijIdeaCommunity("2024.2.6") + intellijIdea("2024.3.6") bundledPlugin("com.intellij.java") } } @@ -28,12 +31,21 @@ intellijPlatform { pluginConfiguration { ideaVersion { - sinceBuild = "242" + sinceBuild = "243" } } pluginVerification { ides { - recommended() + // since 253, IntelliJ IDEA Community and Ultimate have been merged into IntelliJ IDEA + select { + types = listOf(IntellijIdeaCommunity) + untilBuild = "252.*" + } + select { + types = listOf(IntellijIdea) + sinceBuild = "253" + channels = listOf(RELEASE) + } } } } diff --git a/code_samples/run_configuration/build.gradle.kts b/code_samples/run_configuration/build.gradle.kts index 538ebad0e64..c3fd371576b 100644 --- a/code_samples/run_configuration/build.gradle.kts +++ b/code_samples/run_configuration/build.gradle.kts @@ -1,8 +1,11 @@ // Copyright 2000-2025 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license. +import org.jetbrains.intellij.platform.gradle.IntelliJPlatformType.IntellijIdea +import org.jetbrains.intellij.platform.gradle.IntelliJPlatformType.IntellijIdeaCommunity +import org.jetbrains.intellij.platform.gradle.models.ProductRelease.Channel.RELEASE plugins { id("java") - id("org.jetbrains.intellij.platform") version "2.6.0" + id("org.jetbrains.intellij.platform") version "2.10.4" } group = "org.intellij.sdk" @@ -18,7 +21,7 @@ repositories { dependencies { intellijPlatform { - intellijIdeaCommunity("2024.2.6") + intellijIdea("2024.3.6") } } @@ -27,12 +30,21 @@ intellijPlatform { pluginConfiguration { ideaVersion { - sinceBuild = "242" + sinceBuild = "243" } } pluginVerification { ides { - recommended() + // since 253, IntelliJ IDEA Community and Ultimate have been merged into IntelliJ IDEA + select { + types = listOf(IntellijIdeaCommunity) + untilBuild = "252.*" + } + select { + types = listOf(IntellijIdea) + sinceBuild = "253" + channels = listOf(RELEASE) + } } } } diff --git a/code_samples/run_configuration/src/main/java/org/jetbrains/sdk/runConfiguration/DemoSettingsEditor.java b/code_samples/run_configuration/src/main/java/org/jetbrains/sdk/runConfiguration/DemoSettingsEditor.java index bdd3f9c97be..6dd66b5addd 100644 --- a/code_samples/run_configuration/src/main/java/org/jetbrains/sdk/runConfiguration/DemoSettingsEditor.java +++ b/code_samples/run_configuration/src/main/java/org/jetbrains/sdk/runConfiguration/DemoSettingsEditor.java @@ -16,8 +16,8 @@ public class DemoSettingsEditor extends SettingsEditor { public DemoSettingsEditor() { scriptPathField = new TextFieldWithBrowseButton(); - scriptPathField.addBrowseFolderListener("Select Script File", null, null, - FileChooserDescriptorFactory.createSingleFileDescriptor()); + scriptPathField.addBrowseFolderListener(null, + FileChooserDescriptorFactory.createSingleFileDescriptor().withTitle("Select Script File")); myPanel = FormBuilder.createFormBuilder() .addLabeledComponent("Script file", scriptPathField) .getPanel(); diff --git a/code_samples/settings/build.gradle.kts b/code_samples/settings/build.gradle.kts index 538ebad0e64..c3fd371576b 100644 --- a/code_samples/settings/build.gradle.kts +++ b/code_samples/settings/build.gradle.kts @@ -1,8 +1,11 @@ // Copyright 2000-2025 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license. +import org.jetbrains.intellij.platform.gradle.IntelliJPlatformType.IntellijIdea +import org.jetbrains.intellij.platform.gradle.IntelliJPlatformType.IntellijIdeaCommunity +import org.jetbrains.intellij.platform.gradle.models.ProductRelease.Channel.RELEASE plugins { id("java") - id("org.jetbrains.intellij.platform") version "2.6.0" + id("org.jetbrains.intellij.platform") version "2.10.4" } group = "org.intellij.sdk" @@ -18,7 +21,7 @@ repositories { dependencies { intellijPlatform { - intellijIdeaCommunity("2024.2.6") + intellijIdea("2024.3.6") } } @@ -27,12 +30,21 @@ intellijPlatform { pluginConfiguration { ideaVersion { - sinceBuild = "242" + sinceBuild = "243" } } pluginVerification { ides { - recommended() + // since 253, IntelliJ IDEA Community and Ultimate have been merged into IntelliJ IDEA + select { + types = listOf(IntellijIdeaCommunity) + untilBuild = "252.*" + } + select { + types = listOf(IntellijIdea) + sinceBuild = "253" + channels = listOf(RELEASE) + } } } } diff --git a/code_samples/simple_language_plugin/build.gradle.kts b/code_samples/simple_language_plugin/build.gradle.kts index 63814b1a326..d32a2001584 100644 --- a/code_samples/simple_language_plugin/build.gradle.kts +++ b/code_samples/simple_language_plugin/build.gradle.kts @@ -1,9 +1,12 @@ // Copyright 2000-2025 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license. +import org.jetbrains.intellij.platform.gradle.IntelliJPlatformType.IntellijIdea +import org.jetbrains.intellij.platform.gradle.IntelliJPlatformType.IntellijIdeaCommunity import org.jetbrains.intellij.platform.gradle.TestFrameworkType +import org.jetbrains.intellij.platform.gradle.models.ProductRelease.Channel.RELEASE plugins { id("java") - id("org.jetbrains.intellij.platform") version "2.6.0" + id("org.jetbrains.intellij.platform") version "2.10.4" } group = "org.intellij.sdk" @@ -28,7 +31,7 @@ repositories { dependencies { intellijPlatform { - intellijIdeaCommunity("2024.2.6") + intellijIdea("2024.3.6") bundledPlugin("com.intellij.java") testFramework(TestFrameworkType.Plugin.Java) @@ -45,12 +48,21 @@ intellijPlatform { pluginConfiguration { ideaVersion { - sinceBuild = "242" + sinceBuild = "243" } } pluginVerification { ides { - recommended() + // since 253, IntelliJ IDEA Community and Ultimate have been merged into IntelliJ IDEA + select { + types = listOf(IntellijIdeaCommunity) + untilBuild = "252.*" + } + select { + types = listOf(IntellijIdea) + sinceBuild = "253" + channels = listOf(RELEASE) + } } } } diff --git a/code_samples/theme_basics/README.md b/code_samples/theme_basics/README.md index 6fd58d3275d..f9d20f80c03 100644 --- a/code_samples/theme_basics/README.md +++ b/code_samples/theme_basics/README.md @@ -40,4 +40,4 @@ It describes definitions of the actions, extensions, or listeners provided by th To run the `theme_basics` plugin make sure that module SDK is correctly set up and points to IntelliJ Platform Plugin SDK, e.g. `IntelliJ IDEA IC-`. To check this, go to **File | Project Structure | Project Settings | Modules | theme_basics** and select **Dependencies** tab. -If the required SDK doesn't exist, it can be added in **File | Project Structure | Platform Settings | SDKs** by clicking the plus button and selecting **Add IntelliJ Platform Plugin SDK...** item. +If the required SDK doesn't exist, it can be added in **File | Project Structure | Platform Settings | SDKs** by clicking the plus button and selecting **Add IntelliJ Platform Plugin SDK from disk...** item. diff --git a/code_samples/tool_window/build.gradle.kts b/code_samples/tool_window/build.gradle.kts index 538ebad0e64..c3fd371576b 100644 --- a/code_samples/tool_window/build.gradle.kts +++ b/code_samples/tool_window/build.gradle.kts @@ -1,8 +1,11 @@ // Copyright 2000-2025 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license. +import org.jetbrains.intellij.platform.gradle.IntelliJPlatformType.IntellijIdea +import org.jetbrains.intellij.platform.gradle.IntelliJPlatformType.IntellijIdeaCommunity +import org.jetbrains.intellij.platform.gradle.models.ProductRelease.Channel.RELEASE plugins { id("java") - id("org.jetbrains.intellij.platform") version "2.6.0" + id("org.jetbrains.intellij.platform") version "2.10.4" } group = "org.intellij.sdk" @@ -18,7 +21,7 @@ repositories { dependencies { intellijPlatform { - intellijIdeaCommunity("2024.2.6") + intellijIdea("2024.3.6") } } @@ -27,12 +30,21 @@ intellijPlatform { pluginConfiguration { ideaVersion { - sinceBuild = "242" + sinceBuild = "243" } } pluginVerification { ides { - recommended() + // since 253, IntelliJ IDEA Community and Ultimate have been merged into IntelliJ IDEA + select { + types = listOf(IntellijIdeaCommunity) + untilBuild = "252.*" + } + select { + types = listOf(IntellijIdea) + sinceBuild = "253" + channels = listOf(RELEASE) + } } } } diff --git a/code_samples/tree_structure_provider/build.gradle.kts b/code_samples/tree_structure_provider/build.gradle.kts index 538ebad0e64..c3fd371576b 100644 --- a/code_samples/tree_structure_provider/build.gradle.kts +++ b/code_samples/tree_structure_provider/build.gradle.kts @@ -1,8 +1,11 @@ // Copyright 2000-2025 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license. +import org.jetbrains.intellij.platform.gradle.IntelliJPlatformType.IntellijIdea +import org.jetbrains.intellij.platform.gradle.IntelliJPlatformType.IntellijIdeaCommunity +import org.jetbrains.intellij.platform.gradle.models.ProductRelease.Channel.RELEASE plugins { id("java") - id("org.jetbrains.intellij.platform") version "2.6.0" + id("org.jetbrains.intellij.platform") version "2.10.4" } group = "org.intellij.sdk" @@ -18,7 +21,7 @@ repositories { dependencies { intellijPlatform { - intellijIdeaCommunity("2024.2.6") + intellijIdea("2024.3.6") } } @@ -27,12 +30,21 @@ intellijPlatform { pluginConfiguration { ideaVersion { - sinceBuild = "242" + sinceBuild = "243" } } pluginVerification { ides { - recommended() + // since 253, IntelliJ IDEA Community and Ultimate have been merged into IntelliJ IDEA + select { + types = listOf(IntellijIdeaCommunity) + untilBuild = "252.*" + } + select { + types = listOf(IntellijIdea) + sinceBuild = "253" + channels = listOf(RELEASE) + } } } } diff --git a/ijs.tree b/ijs.tree index ce7b598cf51..9ffee357551 100644 --- a/ijs.tree +++ b/ijs.tree @@ -59,6 +59,7 @@ + @@ -87,7 +88,7 @@ - + @@ -143,6 +144,7 @@ + @@ -232,6 +234,7 @@ + @@ -260,11 +263,11 @@ - - - - - + + + + + @@ -386,7 +389,7 @@ - + @@ -451,6 +454,7 @@ + @@ -470,10 +474,12 @@ + + @@ -493,13 +499,11 @@ - - @@ -525,7 +529,6 @@ - diff --git a/images/custom_language_support/websymbols_web_types.svg b/images/custom_language_support/polysymbols_web_types.svg similarity index 99% rename from images/custom_language_support/websymbols_web_types.svg rename to images/custom_language_support/polysymbols_web_types.svg index 5c75cf7538c..3474e357c42 100644 --- a/images/custom_language_support/websymbols_web_types.svg +++ b/images/custom_language_support/polysymbols_web_types.svg @@ -1,4 +1,6 @@ + + + + -: Override new method [`JsonWidgetSuppressor.isCandidateForSuppress(VirtualFile, Project)`](%gh-ic%/json/src/com/jetbrains/jsonSchema/extension/JsonWidgetSuppressor.java) for quick check in [EDT](threading_model.md) before `suppressSwitcherWidget()` is called on a background thread. +: Override new method [`JsonWidgetSuppressor.isCandidateForSuppress(VirtualFile, Project)`](%gh-ic%/json/backend/src/com/jetbrains/jsonSchema/extension/JsonWidgetSuppressor.java) for quick check in [EDT](threading_model.md) before `suppressSwitcherWidget()` is called on a background thread. ### HTTP Client Plugin 2021.1 diff --git a/reference_guide/api_changes_list_2025.md b/reference_guide/api_changes_list_2025.md index 55590f64706..9e27d56f4ba 100644 --- a/reference_guide/api_changes_list_2025.md +++ b/reference_guide/api_changes_list_2025.md @@ -69,16 +69,75 @@ NOTE: Entries not starting with code quotes (`name`) can be added to document no +## 2025.3 + +### IntelliJ Platform 2025.3 + +Several modules were extracted from the core plugin to separate modules with their own classloaders. +This shouldn't affect binary compatibility, but an explicit dependency should be added in `build.gradle.kts` using `bundledModule()` if a plugin uses API from these modules: +* `intellij.platform.collaborationTools.auth.base` +* `intellij.platform.collaborationTools.auth` +* `intellij.platform.scriptDebugger.backend` +* `intellij.platform.scriptDebugger.protocolReaderRuntime` +* `intellij.platform.scriptDebugger.ui` +* `intellij.platform.vcs.dvcs` +* `intellij.platform.vcs.log` +* `intellij.platform.vcs.log.graph` + +The annotation `com.intellij.openapi.components.Storage` cannot be used at top-level +: Actually, it has never been correct. +The annotation can be used only in [`@State.storages`](%gh-ic%/platform/projectModel-api/src/com/intellij/openapi/components/State.java). +See [IJPL-207245](https://youtrack.jetbrains.com/issue/IJPL-207245) for details. + +The `org.intellij.intelliLang` plugin requires Gradle dependency on bundled module `intellij.platform.langInjection` +: Change `bundledPlugin("org.intellij.intelliLang")` to `bundledModule("intellij.platform.langInjection")` in Gradle build script. + ## 2025.2 ### IntelliJ Platform 2025.2 +Several modules were extracted from the core plugin to separate modules with their own classloaders. +This shouldn't affect binary compatibility, but an explicit dependency should be added in `build.gradle.kts` using `bundledModule()` if a plugin uses API from these modules: +* `intellij.platform.tasks` +* `intellij.spellchecker` +* `intellij.relaxng` + `icons.JavaUltimateIcons` class moved to package `com.intellij.java.ultimate.icons` : Update code usages and make sure your plugin [depends](plugin_dependencies.md) on the Java plugin. `com.intellij.psi.xml.HtmlFileElementType.getHtmlStubVersion()` method removed : Use `com.intellij.xml.HtmlLanguageStubVersionUtil.getHtmlStubVersion()` instead. +`com.intellij.openapi.actionSystem.ActionGroup.getChildren(AnActionEvent, ActionManager)` method removed +: Avoid expanding an action group manually + +`com.intellij.openapi.actionSystem.DefaultActionGroup.getChildren(AnActionEvent, ActionManager)` method removed +: Avoid expanding an action group manually or use `DefaultActionGroup.getChildren(ActionManager)` + +`com.intellij.diff.util.ThreeSide.map(Function)` method parameter type changed from `com.intellij.util.Function` to `kotlin.jvm.functions.Function1` +: Use `kotlin.jvm.functions.Function1` as a parameter. + +The experimental `com.intellij.webSymbols` package together with all the classes and extension points has been renamed to `com.intellij.polySymbols`. +: The classes were renamed using pattern `WebSymbol[s]?(.*)` -> `PolySymbol$1`. Some classes have also been moved +to more specific packages. +: From other notable changes: +1. `PolySymbol` interface no longer extends `PolySymbolScope` +2. `PolySymbol` interface no longer contains documentation-specific properties (`description`, `docUrl`, `sections` and `defaultValue`), + instead `getDocumentationTarget` method should be overridden and the new `PolySymbolDocumentationTarget.create` method + used to lazily build documentation for the symbol +3. `PolySymbol` no longer has `abstract`, `required` and `virtual` properties. They've been replaced by a more + generic `modifiers` property +4. `PolySymbol` no longer has `properties` property, which returned a map of properties. It's been replaced by + `get` method, which should return value for the requested property. +5. `PolySymbol` no longer has `attributeValue` property, instead `get` method should be overridden to return + the value for `com.intellij.polySymbols.html.PROP_HTML_ATTRIBUTE_VALUE` property +6. The `WebSymbolsQueryConfigurator$getScope` has been removed and replaced with a pattern-based `PolySymbolQueryScopeContributor` API +7. The `PolySymbolDelegate` and `PsiSourcePolySymbolDelegate` are interfaces now +8. All APIs have been refactored to use `PolySymbolQualifiedKind` instead of separate parameters `namespace` and `kind` +9. Builder patterns have been introduced in various classes, like `PolySymbolQueryExecutor`, `PolySymbolQueryParams`, or `PolySymbolDocumentation` + instead of now removed Kotlin methods with default parameters. +: Please note that the module is under active development and further major API changes are to be expected in the upcoming releases. + ### Package Checker 2025.2 `com.intellij.packageChecker.api.PackageDeclaration(Package)` method parameter type changed from `org.jetbrains.security.package.Package` to `com.intellij.packageChecker.model.Package` @@ -134,6 +193,17 @@ NOTE: Entries not starting with code quotes (`name`) can be added to document no `com.intellij.lang.javascript.JSStubElementTypes.EMBEDDED_CONTENT` field type changed from `com.intellij.psi.tree.IElementType` to `com.intellij.lang.javascript.psi.JSElementType` : Recompile code usages. +`org.jetbrains.vuejs.lang.expr.VueJSLanguage.Companion` class removed +: Use `org.jetbrains.vuejs.lang.expr.VueJSLanguage` instead. + +### Kubernetes Plugin 2025.2 + +`com.intellij.kubernetes.api.KubernetesApiProvider.getInstance(Project)` method return type changed from `com.intellij.kubernetes.api.KubernetesApiProvider` to `com.intellij.kubernetes.api.KubernetesApiProviderInterface` +: Update code usages. + +`com.intellij.kubernetes.api.KubernetesApiProvider.State`class renamed to `com.intellij.kubernetes.api.KubernetesApiProviderInterface.KubeconfigState` +: Update code usages. + ## 2025.1 ### IntelliJ Platform 2025.1 @@ -164,6 +234,9 @@ Class `com.intellij.psi.xml.XmlElementType` no longer extends `com.intellij.psi. `xml.parsing.unescaped.ampersand.or.nonterminated.character.entity.reference` property removed from resource bundle `messages.XmlPsiBundle` : Use property from resource bundle `messages.XmlParserBundle` +Kotlin UI DSL Version 1 must not be used from 2025.1 +: [Migrate to Kotlin UI DSL Version 2](kotlin_ui_dsl.md#migration-to-version-2). + ### Database Plugin 2025.1 `com.intellij.database.view.models` package removed diff --git a/topics/_generated/android_studio_releases.md b/topics/_generated/android_studio_releases.md index df7233b8fbb..550ec907a88 100644 --- a/topics/_generated/android_studio_releases.md +++ b/topics/_generated/android_studio_releases.md @@ -6,11 +6,47 @@ | Release Name | Channel | Version | IntelliJ IDEA Version | Release Date | |--------------|---------|---------|-----------------------|--------------| +|

    Otter 2 Feature Drop

    2025.2.2 Canary 4

    | ![Canary][canary] | **2025.2.2.4**

    AI‑252.27397.103.2522.14395761

    | **2025.2.4**

    252.27397.103

    | Nov 6, 2025 | +|

    Otter 2 Feature Drop

    2025.2.2 Canary 3

    | ![Canary][canary] | **2025.2.2.3**

    AI‑252.25557.131.2522.14357309

    | **2025.2.1**

    252.25557.131

    | Oct 30, 2025 | +|

    Otter 2 Feature Drop

    2025.2.2 Canary 2

    | ![Canary][canary] | **2025.2.2.2**

    AI‑252.25557.131.2522.14326795

    | **2025.2.1**

    252.25557.131

    | Oct 28, 2025 | +|

    Otter 2 Feature Drop

    2025.2.2 Canary 1

    | ![Canary][canary] | **2025.2.2.1**

    AI‑252.25557.131.2522.14279661

    | **2025.2.1**

    252.25557.131

    | Oct 16, 2025 | +|

    Otter

    2025.2.1

    | ![Release][release] | **2025.2.1.7**

    AI‑252.25557.131.2521.14344949

    | **2025.2.1**

    252.25557.131

    | Oct 30, 2025 | +|

    Otter

    2025.2.1 RC 1

    | ![RC][rc] | **2025.2.1.6**

    AI‑252.25557.131.2521.14270146

    | **2025.2.1**

    252.25557.131

    | Oct 16, 2025 | +|

    Otter

    2025.2.1 Canary 5

    | ![Canary][canary] | **2025.2.1.5**

    AI‑252.25557.131.2521.14240541

    | **2025.2.1**

    252.25557.131

    | Oct 9, 2025 | +|

    Otter

    2025.2.1 Canary 4

    | ![Canary][canary] | **2025.2.1.4**

    AI‑252.25557.131.2521.14204915

    | **2025.2.1**

    252.25557.131

    | Oct 2, 2025 | +|

    Otter

    2025.2.1 Canary 3

    | ![Canary][canary] | **2025.2.1.3**

    AI‑252.25557.131.2521.14170811

    | **2025.2.1**

    252.25557.131

    | Sep 26, 2025 | +|

    Otter

    2025.2.1 Canary 2

    | ![Canary][canary] | **2025.2.1.2**

    AI‑252.25557.131.2521.14165931

    | **2025.2.1**

    252.25557.131

    | Sep 25, 2025 | +|

    Otter

    2025.2.1 Canary 1

    | ![Canary][canary] | **2025.2.1.1**

    AI‑252.25557.131.2521.14126747

    | **2025.2.1**

    252.25557.131

    | Sep 22, 2025 | +|

    Narwhal 4 Feature Drop

    2025.1.4

    | ![Release][release] | **2025.1.4.8**

    AI‑251.27812.49.2514.14217341

    | **2025.1.5**

    251.27812.49

    | Oct 9, 2025 | +|

    Narwhal 4 Feature Drop

    2025.1.4 RC 2

    | ![RC][rc] | **2025.1.4.7**

    AI‑251.27812.49.2514.14171003

    | **2025.1.5**

    251.27812.49

    | Sep 29, 2025 | +|

    Narwhal 4 Feature Drop

    2025.1.4 RC 1

    | ![RC][rc] | **2025.1.4.6**

    AI‑251.27812.49.2514.14156358

    | **2025.1.5**

    251.27812.49

    | Sep 24, 2025 | +|

    Narwhal 4 Feature Drop

    2025.1.4 Canary 5

    | ![Canary][canary] | **2025.1.4.5**

    AI‑251.27812.49.2514.14085407

    | **2025.1.5**

    251.27812.49

    | Sep 11, 2025 | +|

    Narwhal 4 Feature Drop

    2025.1.4 Canary 4

    | ![Canary][canary] | **2025.1.4.4**

    AI‑251.27812.49.2514.14044074

    | **2025.1.5**

    251.27812.49

    | Sep 4, 2025 | +|

    Narwhal 4 Feature Drop

    2025.1.4 Canary 3

    | ![Canary][canary] | **2025.1.4.3**

    AI‑251.27812.49.2514.14014849

    | **2025.1.5**

    251.27812.49

    | Aug 29, 2025 | +|

    Narwhal 4 Feature Drop

    2025.1.4 Canary 2

    | ![Canary][canary] | **2025.1.4.2**

    AI‑251.27812.49.2514.13971338

    | **2025.1.5**

    251.27812.49

    | Aug 21, 2025 | +|

    Narwhal 4 Feature Drop

    2025.1.4 Canary 1

    | ![Canary][canary] | **2025.1.4.1**

    AI‑251.26094.121.2514.13932717

    | **2025.1.2**

    251.26094.121

    | Aug 14, 2025 | +|

    Narwhal 3 Feature Drop

    2025.1.3

    | ![Release][release] | **2025.1.3.7**

    AI‑251.26094.121.2513.14007798

    | **2025.1.2**

    251.26094.121

    | Sep 2, 2025 | +|

    Narwhal 3 Feature Drop

    2025.1.3 RC 2

    | ![RC][rc] | **2025.1.3.6**

    AI‑251.26094.121.2513.13991806

    | **2025.1.2**

    251.26094.121

    | Aug 28, 2025 | +|

    Narwhal 3 Feature Drop

    2025.1.3 RC 1

    | ![RC][rc] | **2025.1.3.5**

    AI‑251.26094.121.2513.13930206

    | **2025.1.2**

    251.26094.121

    | Aug 14, 2025 | +|

    Narwhal 3 Feature Drop

    2025.1.3 Canary 4

    | ![Canary][canary] | **2025.1.3.4**

    AI‑251.26094.121.2513.13898001

    | **2025.1.2**

    251.26094.121

    | Aug 7, 2025 | +|

    Narwhal Feature Drop

    2025.1.3 Canary 3

    | ![Canary][canary] | **2025.1.3.3**

    AI‑251.26094.121.2513.13865387

    | **2025.1.2**

    251.26094.121

    | Jul 31, 2025 | +|

    Narwhal Feature Drop

    2025.1.3 Canary 2

    | ![Canary][canary] | **2025.1.3.2**

    AI‑251.26094.121.2513.13829813

    | **2025.1.2**

    251.26094.121

    | Jul 24, 2025 | +|

    Narwhal Feature Drop

    2025.1.3 Canary 1

    | ![Canary][canary] | **2025.1.3.1**

    AI‑251.26094.121.2513.13793675

    | **2025.1.2**

    251.26094.121

    | Jul 21, 2025 | +|

    Narwhal Feature Drop

    2025.1.2 Patch 2

    | ![Patch][patch] | **2025.1.2.13**

    AI‑251.26094.121.2512.13991807

    | **2025.1.2**

    251.26094.121

    | Aug 28, 2025 | +|

    Narwhal Feature Drop

    2025.1.2 Patch 1

    | ![Patch][patch] | **2025.1.2.12**

    AI‑251.26094.121.2512.13930704

    | **2025.1.2**

    251.26094.121

    | Aug 18, 2025 | +|

    Narwhal Feature Drop

    2025.1.2

    | ![Release][release] | **2025.1.2.11**

    AI‑251.26094.121.2512.13840223

    | **2025.1.2**

    251.26094.121

    | Jul 31, 2025 | +|

    Narwhal Feature Drop

    2025.1.2 RC 1

    | ![RC][rc] | **2025.1.2.10**

    AI‑251.26094.121.2512.13795096

    | **2025.1.2**

    251.26094.121

    | Jul 18, 2025 | +|

    Narwhal Feature Drop

    2025.1.2 Canary 9

    | ![Canary][canary] | **2025.1.2.9**

    AI‑251.26094.121.2512.13760328

    | **2025.1.2**

    251.26094.121

    | Jul 14, 2025 | +|

    Narwhal Feature Drop

    2025.1.2 Canary 8

    | ![Canary][canary] | **2025.1.2.8**

    AI‑251.26094.121.2512.13728066

    | **2025.1.2**

    251.26094.121

    | Jul 2, 2025 | +|

    Narwhal Feature Drop

    2025.1.2 Canary 7

    | ![Canary][canary] | **2025.1.2.7**

    AI‑251.26094.121.2512.13699665

    | **2025.1.2**

    251.26094.121

    | Jun 26, 2025 | +|

    Narwhal Feature Drop

    2025.1.2 Canary 6

    | ![Canary][canary] | **2025.1.2.6**

    AI‑251.26094.121.2512.13669762

    | **2025.1.2**

    251.26094.121

    | Jun 20, 2025 | |

    Narwhal Feature Drop

    2025.1.2 Canary 5

    | ![Canary][canary] | **2025.1.2.5**

    AI‑251.26094.121.2512.13636022

    | **2025.1.2**

    251.26094.121

    | Jun 13, 2025 | |

    Narwhal Feature Drop

    2025.1.2 Canary 4

    | ![Canary][canary] | **2025.1.2.4**

    AI‑251.26094.121.2512.13602698

    | **2025.1.2**

    251.26094.121

    | Jun 6, 2025 | |

    Narwhal Feature Drop

    2025.1.2 Canary 3

    | ![Canary][canary] | **2025.1.2.3**

    AI‑251.25410.109.2512.13571611

    | **2025.1.1**

    251.25410.109

    | May 29, 2025 | |

    Narwhal Feature Drop

    2025.1.2 Canary 2

    | ![Canary][canary] | **2025.1.2.2**

    AI‑251.25410.109.2512.13536108

    | **2025.1.1**

    251.25410.109

    | May 22, 2025 | |

    Narwhal Feature Drop

    2025.1.2 Canary 1

    | ![Canary][canary] | **2025.1.2.1**

    AI‑251.25410.109.2512.13514151

    | **2025.1.1**

    251.25410.109

    | May 20, 2025 | +|

    Narwhal

    2025.1.1 Patch 1

    | ![Patch][patch] | **2025.1.1.14**

    AI‑251.25410.109.2511.13752376

    | **2025.1.1**

    251.25410.109

    | Jul 10, 2025 | +|

    Narwhal

    2025.1.1

    | ![Release][release] | **2025.1.1.13**

    AI‑251.25410.109.2511.13665796

    | **2025.1.1**

    251.25410.109

    | Jun 24, 2025 | |

    Narwhal

    2025.1.1 RC 2

    | ![RC][rc] | **2025.1.1.12**

    AI‑251.25410.109.2511.13625888

    | **2025.1.1**

    251.25410.109

    | Jun 12, 2025 | |

    Narwhal

    2025.1.1 RC 1

    | ![RC][rc] | **2025.1.1.11**

    AI‑251.25410.109.2511.13569669

    | **2025.1.1**

    251.25410.109

    | Jun 3, 2025 | |

    Narwhal

    2025.1.1 Canary 10

    | ![Canary][canary] | **2025.1.1.10**

    AI‑251.23774.435.2511.13464725

    | **2025.1**

    251.23774.435

    | May 8, 2025 | diff --git a/topics/appendix/api_internal/api_internal.md b/topics/appendix/api_internal/api_internal.md index 92d69e85e0f..c0b07408d0c 100644 --- a/topics/appendix/api_internal/api_internal.md +++ b/topics/appendix/api_internal/api_internal.md @@ -8,6 +8,13 @@ Lists private APIs and their replacements in IntelliJ Platform and plugins. Lists private API annotated with @ApiStatus.Internal/@IntellijInternalApi and corresponding replacement. +> How to address the **private API** usage violations: +> 1. Look through the suggested replacements below, update your plugin accordingly, and upload a new version to JetBrains Marketplace. +> 2. If you need help with the replacements, please [create a YouTrack issue](https://youtrack.jetbrains.com/newIssue?project=IJPL&c=Type%20Task&c=Subsystem%20Internal%20API). +> Please note that we may not be able to provide a replacement quickly, and in some cases, a replacement might not be available at all. +> 3. If you have any other issues or questions related to the Internal API usage, please [create a dedicated YouTrack issue](https://youtrack.jetbrains.com/newIssue?project=IJPL&c=Type%20Task&c=Subsystem%20Internal%20API). +> + This page lists commonly used API annotated with [`@ApiStatus.Internal`](%gh-java-annotations%/common/src/main/java/org/jetbrains/annotations/ApiStatus.java) or [`@IntellijInternalApi`](%gh-ic%/platform/util/src/com/intellij/openapi/util/IntellijInternalApi.kt) which indicates it is _private API_ and must not be used outside of IntelliJ Platform itself: @@ -38,33 +45,34 @@ Each entry is mapped to its corresponding _Replacement_, pointing to the recomme ## IntelliJ Platform -| Internal API | Replacement | -|-------------------------------------------------------------------------------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| -| `AnAction.applyTextOverride()` | [](plugin_configuration_file.md#idea-plugin__actions__action__override-text) | -| `ApplicationLoadListener` | See [](plugin_components.md#application-startup) | -| `BuildNumber.currentVersion()` | Use `ApplicationInfo.getBuild()` | -| `CompactVirtualFileSet` | Use `VfsUtilCore.createCompactVirtualFileSet()` | -| `DefaultPicoContainer` | Use [extension points](plugin_extensions.md) and [services](plugin_services.md) | -| `ExperimentalUI.isNewUI()` | Use [`NewUI.isEnabled()`](%gh-ic%/platform/platform-api/src/com/intellij/ui/NewUI.java) | -| `FileTypeIndex.NAME` | Use static methods in `FileTypeIndex` directly | -| `IElementType.getDebugName()` | Override/use `IElementType.toString()` | -| `IconLoader.CachedImageIcon` | Use methods exposed in `IconLoader` | -| `IconLoader.LazyIcon` | Use `IconLoader.createLazy()` | -| `IndexingDataKeys` | [See Doc](%gh-ic%/platform/core-impl/src/com/intellij/util/indexing/IndexingDataKeys.java) | -| `Module.getModuleFile()` | [See Doc](%gh-ic%/platform/core-api/src/com/intellij/openapi/module/Module.java) | -| `Module.getModuleFilePath()` | [See Doc](%gh-ic%/platform/core-api/src/com/intellij/openapi/module/Module.java) | -| `Module.getModuleTypeName()` | [See Doc](%gh-ic%/platform/core-api/src/com/intellij/openapi/module/Module.java) | -| `ModuleTypeManager.registerModuleType()` | Use instead. [`ModuleType`](%gh-ic%/platform/lang-core/src/com/intellij/openapi/module/ModuleType.java) | -| `PathMacros.setMacro()` | Use . [`PathMacroContributor`](%gh-ic%/platform/core-api/src/com/intellij/openapi/application/PathMacroContributor.java) | -| `PlatformUtils` | [See Doc](%gh-ic%/platform/core-api/src/com/intellij/util/PlatformUtils.java) | -| `PluginClassLoader` | Cast to [`PluginAwareClassLoader`](%gh-ic%/platform/extensions/src/com/intellij/ide/plugins/cl/PluginAwareClassLoader.java) | -| `PluginManager.getLogger()` | Use own logger, see [](ide_infrastructure.md#logging) | -| `PreloadingActivity` | Use `StartupActivity.Background` ([docs](plugin_components.md#project-open)) with atomic flag to run only once during IDE lifetime | -| `ProjectLibraryTable` | Use `LibraryTablesRegistrar.getLibraryTable()` | -| `SVGLoader` | Use `ImageLoader.loadFromResource()` | -| `ScrollBarPainter` | [See Doc](%gh-ic%/platform/platform-api/src/com/intellij/ui/components/ScrollBarPainter.java) | -| `ToolWindowManager.registerToolWindow(String, RegisterToolWindowTaskBuilder)` | [False positive](https://youtrack.jetbrains.com/issue/MP-6705) from [Plugin Verifier](verifying_plugin_compatibility.md) | -| `UtilKt.targetPresentation()` | [See Doc](%gh-ic%/platform/lang-impl/src/com/intellij/codeInsight/navigation/util.kt) | +| Internal API | Replacement | +|-------------------------------------------------------------------------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| `AnAction.applyTextOverride()` | [](plugin_configuration_file.md#idea-plugin__actions__action__override-text) | +| `ApplicationLoadListener` | See [](plugin_components.md#application-startup) | +| `BuildNumber.currentVersion()` | Use `ApplicationInfo.getBuild()` | +| `CompactVirtualFileSet` | Use `VfsUtilCore.createCompactVirtualFileSet()` | +| `DefaultPicoContainer` | Use [extension points](plugin_extensions.md) and [services](plugin_services.md) | +| `ExperimentalUI.isNewUI()` | Use [`NewUI.isEnabled()`](%gh-ic%/platform/platform-api/src/com/intellij/ui/NewUI.java) | +| `FileTypeIndex.NAME` | Use static methods in `FileTypeIndex` directly | +| `IElementType.getDebugName()` | Override/use `IElementType.toString()` | +| `IconLoader.CachedImageIcon` | Use methods exposed in `IconLoader` | +| `IconLoader.LazyIcon` | Use `IconLoader.createLazy()` | +| `IndexingDataKeys` | [See Doc](%gh-ic%/platform/core-impl/src/com/intellij/util/indexing/IndexingDataKeys.java) | +| `Module.getModuleFile()` | [See Doc](%gh-ic%/platform/core-api/src/com/intellij/openapi/module/Module.java) | +| `Module.getModuleFilePath()` | [See Doc](%gh-ic%/platform/core-api/src/com/intellij/openapi/module/Module.java) | +| `Module.getModuleTypeName()` | [See Doc](%gh-ic%/platform/core-api/src/com/intellij/openapi/module/Module.java) | +| `ModuleTypeManager.registerModuleType()` | Use instead. [`ModuleType`](%gh-ic%/platform/lang-core/src/com/intellij/openapi/module/ModuleType.java) | +| `PathMacros.setMacro()` | Use . [`PathMacroContributor`](%gh-ic%/platform/core-api/src/com/intellij/openapi/application/PathMacroContributor.java) | +| `PlatformUtils` | [See Doc](%gh-ic%/platform/core-api/src/com/intellij/util/PlatformUtils.java) | +| `PluginClassLoader` | Cast to [`PluginAwareClassLoader`](%gh-ic%/platform/extensions/src/com/intellij/ide/plugins/cl/PluginAwareClassLoader.java) | +| `PluginManager.getLogger()` | Use own logger, see [](ide_infrastructure.md#logging) | +| `PreloadingActivity` | Use `StartupActivity.Background` ([docs](plugin_components.md#project-open)) with atomic flag to run only once during IDE lifetime | +| `ProjectLibraryTable` | Use `LibraryTablesRegistrar.getLibraryTable()` | +| `SVGLoader` | Use `ImageLoader.loadFromResource()` | +| `ScrollBarPainter` | [See Doc](%gh-ic%/platform/platform-api/src/com/intellij/ui/components/ScrollBarPainter.java) | +| `ToolWindowManager.registerToolWindow(String, RegisterToolWindowTaskBuilder)` | [False positive](https://youtrack.jetbrains.com/issue/MP-6705) from [Plugin Verifier](verifying_plugin_compatibility.md) | +| `UtilKt.targetPresentation()` | [See Doc](%gh-ic%/platform/lang-impl/src/com/intellij/codeInsight/navigation/util.kt) | +| `TextEditorCustomizer` | Use and customize editor in [`EditorFactoryListener.editorCreated()`](%gh-ic%/platform/editor-ui-api/src/com/intellij/openapi/editor/event/EditorFactoryListener.java).
    Get the editor instance with `TextEditorProvider.getTextEditor()` passing `event.editor`. | ## Plugins @@ -88,7 +96,7 @@ Therefore, any reported violations can be disregarded. | [`CodeVisionPlaceholderCollector`](%gh-ic%/platform/lang-impl/src/com/intellij/codeInsight/codeVision/CodeVisionPlaceholderCollector.kt) | Made public in 2024.2 | | [`IdFilter`](%gh-ic%/platform/indexing-api/src/com/intellij/util/indexing/IdFilter.java) | Made public in 2021.2/3 | | [`HashingStrategy`](%gh-ic%/platform/util/base/src/com/intellij/util/containers/HashingStrategy.java) | Made public in 2023.1 | -| [`JsonCustomStructureViewFactory`](%gh-ic%/json/src/com/intellij/json/structureView/JsonCustomStructureViewFactory.java) | Made public in 2023.2 | +| [`JsonCustomStructureViewFactory`](%gh-ic%/json/backend/src/com/intellij/json/structureView/JsonCustomStructureViewFactory.java) | Made public in 2023.2 | | [`RunAnythingCommandLineProvider`](%gh-ic%/platform/lang-impl/src/com/intellij/ide/actions/runAnything/activity/RunAnythingCommandLineProvider.kt) | Made public in 2021.3 | | [`SearchEverywhereFoundElementInfo`](%gh-ic%/platform/lang-impl/src/com/intellij/ide/actions/searcheverywhere/SearchEverywhereFoundElementInfo.java) | Made public in 2023.3 | | `PhpExpectedFunctionArgument` | Made public in 2022.1 | diff --git a/topics/appendix/api_notable/api_notable_list_2020.md b/topics/appendix/api_notable/api_notable_list_2020.md index c891921a5b9..2323d0047f4 100644 --- a/topics/appendix/api_notable/api_notable_list_2020.md +++ b/topics/appendix/api_notable/api_notable_list_2020.md @@ -41,6 +41,7 @@ Reader Mode customization Text Editor customization : Implement [`TextEditorCustomizer`](%gh-ic%/platform/platform-impl/src/com/intellij/openapi/fileEditor/impl/text/TextEditorCustomizer.kt) and register in to customize created editors.
    **Note: `TextEditorCustomizer` has been marked internal since 2024.2.** +See [the replacement](api_internal.md#intellij-platform). ### JavaScript Plugin 2020.3 diff --git a/topics/appendix/glossary.md b/topics/appendix/glossary.md index 4c4e1a8cde8..a6796894108 100644 --- a/topics/appendix/glossary.md +++ b/topics/appendix/glossary.md @@ -110,12 +110,12 @@ JetBrains Runtime _(JBR)_ {#jetbrains-runtime} ## N Non-Blocking Read Action _(NBRA)_ {#non-blocking-read-action} -: A → [_Read Action_](#read-action) that is canceled by a → [_Write Action_](#write-action). See also [](threading_model.md#read-action-cancellability). +: A → [_Read Action_](#read-action) that is canceled by a → [_Write Action_](#write-action). See also [](threading_model.md#non-blocking-read-actions). ## P `ProcessCanceledException` _(PCE)_ {#processcanceledexception} -: [`ProcessCanceledException`](%gh-ic%/platform/util/base/src/com/intellij/openapi/progress/ProcessCanceledException.java) An exception indicating that the currently running operation was terminated and should finish as soon as possible. +: [`ProcessCanceledException`](%gh-ic%/platform/util/base/multiplatform/src/com/intellij/openapi/progress/ProcessCanceledException.kt) An exception indicating that the currently running operation was terminated and should finish as soon as possible.
    → [_CancellationException_](#cancellationexception) Program Structure Interface _(PSI)_ {#program-structure-interface} diff --git a/topics/appendix/resources/ep_lists/_generated/generated_android_plugin_extension_point_list.md b/topics/appendix/resources/ep_lists/_generated/generated_android_plugin_extension_point_list.md index 80890465684..3d9ec1b9911 100644 --- a/topics/appendix/resources/ep_lists/_generated/generated_android_plugin_extension_point_list.md +++ b/topics/appendix/resources/ep_lists/_generated/generated_android_plugin_extension_point_list.md @@ -2,7 +2,7 @@ - + - + - + - + - + - + - + - + - + - + - + - + -# IntelliJ Community Plugins Extension Point and Listener List +# IntelliJ Platform Plugins Extension Point and Listener List -Overview of Extension Points and Listeners for IntelliJ Community Plugins. +Overview of Extension Points and Listeners for IntelliJ Platform Plugins. > See [](intellij_platform_extension_point_list.md) for IntelliJ Platform. diff --git a/topics/appendix/resources/explore_api.md b/topics/appendix/resources/explore_api.md index 751137a6c82..50a6130708a 100644 --- a/topics/appendix/resources/explore_api.md +++ b/topics/appendix/resources/explore_api.md @@ -92,7 +92,7 @@ It's important that you're familiar with source code, as well as other basic features of IntelliJ IDEA. Many developers keep the -[IntelliJ Community source code](%gh-ic%/README.md) +[IntelliJ Platform source code](%gh-ic%/README.md) open in a separate IDE project while working on their plugin. Others search the source code of the IntelliJ Platform that is attached by default when using a [Gradle](creating_plugin_project.md)-based project. While both methods work, it should be noted that developing plugins without inspecting the IntelliJ Platform code is nearly impossible, @@ -134,15 +134,15 @@ Note that you need to change the search scope to All Places i If you want to implement a functionality that is similar to an existing IDE feature, but you can't guess the name of the extension point or implementation class, the underlying implementation can be found by the texts displayed in the UI. -* Use the displayed text or its part as the [target for a search](https://www.jetbrains.com/help/idea/finding-and-replacing-text-in-project.html) within the IntelliJ Community project. +* Use the displayed text or its part as the [target for a search](https://www.jetbrains.com/help/idea/finding-and-replacing-text-in-project.html) within the IntelliJ Platform project. * If the text is localized, this will identify a bundle file there the text is defined. Copy the key from the bundle file identified by the search. - * Use the key text as the target for a search within the IntelliJ Community project. + * Use the key text as the target for a search within the IntelliJ Platform project. This search locates the implementation or related class, or [plugin configuration file](plugin_configuration_file.md) that uses the text key in an [extension](plugin_extensions.md) declaration. * If the key is found in the extension declaration in the plugin.xml file, find the implementing class attribute value (in most cases it is `implementationClass`) and [navigate to a declaration](https://www.jetbrains.com/help/rider/Navigation_and_Search__Go_to_Declaration.html#74fa64b7), or use attribute value as the [target of a class search](https://www.jetbrains.com/help/idea/searching-everywhere.html#Searching_Everywhere.xml) - in the IntelliJ Community codebase to find the implementation. + in the IntelliJ Platform codebase to find the implementation. * If the text is not localized, the search will most probably find the desired implementation or related class. In this case, search for the found method/class usages and repeat this until the actual implementation class is found. diff --git a/topics/appendix/resources/useful_links.md b/topics/appendix/resources/useful_links.md index 218cdb769ee..78f05fdf1d0 100644 --- a/topics/appendix/resources/useful_links.md +++ b/topics/appendix/resources/useful_links.md @@ -31,6 +31,6 @@ The following links represent useful resources for working with the IntelliJ Pla * [IntelliJ Platform SDK Documentation](https://github.com/JetBrains/intellij-sdk-docs) & [IntelliJ Platform SDK Code Samples](https://github.com/JetBrains/intellij-sdk-code-samples) * [IntelliJ Platform Plugin Template](https://github.com/JetBrains/intellij-platform-plugin-template) -* [IntelliJ Community Edition](%gh-ic%/README.md) +* [IntelliJ Platform](%gh-ic%/README.md) * [IntelliJ Plugins](https://github.com/JetBrains/intellij-plugins) * [Open Source Plugins on JetBrains Marketplace](https://plugins.jetbrains.com/search?orderBy=name&shouldHaveSource=true) diff --git a/topics/appendix/tools/gradle_intellij_plugin/tools_gradle_intellij_plugin.md b/topics/appendix/tools/gradle_intellij_plugin/tools_gradle_intellij_plugin.md index f020f755a46..31c59bf0347 100644 --- a/topics/appendix/tools/gradle_intellij_plugin/tools_gradle_intellij_plugin.md +++ b/topics/appendix/tools/gradle_intellij_plugin/tools_gradle_intellij_plugin.md @@ -319,11 +319,9 @@ Default value Acceptable values : -- `IC` - [IntelliJ IDEA Community Edition](idea.md) - `IU` - [IntelliJ IDEA Ultimate Edition](idea.md) - `CL` - [CLion](clion.md) - `PY` - [PyCharm Professional Edition](pycharm.md) -- `PC` - [PyCharm Community Edition](pycharm.md) - `PS` - [PhpStorm](phpstorm.md) - `RD` - [Rider](rider.md) - `GO` - [GoLand](goland.md) diff --git a/topics/appendix/tools/ide_tooling/internal_actions/internal_ui_inspector.md b/topics/appendix/tools/ide_tooling/internal_actions/internal_ui_inspector.md index d26bd57315e..595fb9fddb9 100644 --- a/topics/appendix/tools/ide_tooling/internal_actions/internal_ui_inspector.md +++ b/topics/appendix/tools/ide_tooling/internal_actions/internal_ui_inspector.md @@ -91,3 +91,5 @@ These issues are usually invisible in the UI, but they can still prevent users w For each problem, the affected value in the Properties table contains a description that explains what it affects and how to fix it. ![Accessibility Checks](internal_ui_inspector_accessibility_checks.png) + +> Refer to the [accessibility guidelines](accessibility.md) to learn more about accessibility best practices. diff --git a/topics/appendix/tools/intellij_platform_gradle_plugin/tools_intellij_platform_gradle_plugin.md b/topics/appendix/tools/intellij_platform_gradle_plugin/tools_intellij_platform_gradle_plugin.md index c76746f4b08..ce8b956bca7 100644 --- a/topics/appendix/tools/intellij_platform_gradle_plugin/tools_intellij_platform_gradle_plugin.md +++ b/topics/appendix/tools/intellij_platform_gradle_plugin/tools_intellij_platform_gradle_plugin.md @@ -86,7 +86,7 @@ To use the latest snapshot version of this plugin, add the following to the Grad ```kotlin pluginManagement { repositories { - maven("https://oss.sonatype.org/content/repositories/snapshots/") + maven("https://central.sonatype.com/repository/maven-snapshots/") gradlePluginPortal() } } @@ -100,7 +100,7 @@ pluginManagement { pluginManagement { repositories { maven { - url 'https://oss.sonatype.org/content/repositories/snapshots/' + url 'https://central.sonatype.com/repository/maven-snapshots/' } gradlePluginPortal() } @@ -111,7 +111,7 @@ pluginManagement { -> The current IntelliJ Platform Gradle Plugin Snapshot version is ![GitHub Snapshot Release](https://img.shields.io/nexus/s/org.jetbrains.intellij.platform/intellij-platform-gradle-plugin?server=https://oss.sonatype.org&label=) +> The current IntelliJ Platform Gradle Plugin Snapshot version is ![Maven Snapshots](https://img.shields.io/maven-metadata/v?metadataUrl=https%3A%2F%2Fcentral.sonatype.com%2Frepository%2Fmaven-snapshots%2Forg%2Fjetbrains%2Fintellij%2Fplatform%2Fintellij-platform-gradle-plugin%2Fmaven-metadata.xml&label=) > > The snapshot release is published with a fixed version, so Gradle can resort to the cached version of the plugin. > @@ -287,7 +287,7 @@ To switch off the default usage of JetBrains Cache Redirector, see the [](tools_ Dependencies and [repositories](#configuration.repositories) are handled using explicit entries within `dependencies {}` and `repositories {}` blocks in the Gradle build file. -A minimum configuration for targeting IntelliJ IDEA Community 2023.3: +A minimum configuration for targeting IntelliJ IDEA 2024.3: @@ -303,7 +303,7 @@ repositories { dependencies { intellijPlatform { - intellijIdeaCommunity("2023.3") + intellijIdea("2024.3") } } ``` @@ -322,7 +322,7 @@ repositories { dependencies { intellijPlatform { - intellijIdeaCommunity('2023.3') + intellijIdea('2024.3.6') } } ``` @@ -330,8 +330,7 @@ dependencies { - -The `intellijIdeaCommunity` in the previous sample is one of the extension functions available for adding IntelliJ Platform dependencies to the project. +The `intellijIdea` in the previous sample is one of the extension functions available for adding IntelliJ Platform dependencies to the project. See [](tools_intellij_platform_gradle_plugin_dependencies_extension.md) on how to target other IDEs. > When declaring a dependency on IntelliJ Platform, the IDE installer is resolved by default. @@ -489,7 +488,7 @@ repositories { dependencies { intellijPlatform { - intellijIdeaCommunity("%ijPlatform%") + intellijIdea("%ijPlatform%") bundledPlugin("com.intellij.java") plugin("org.intellij.scala", "2024.1.4") @@ -509,7 +508,7 @@ repositories { dependencies { intellijPlatform { - intellijIdeaCommunity '%ijPlatform%' + intellijIdea '%ijPlatform%' bundledPlugin 'com.intellij.java' plugin 'org.intellij.scala', '2024.1.4' diff --git a/topics/appendix/tools/intellij_platform_gradle_plugin/tools_intellij_platform_gradle_plugin_dependencies_extension.md b/topics/appendix/tools/intellij_platform_gradle_plugin/tools_intellij_platform_gradle_plugin_dependencies_extension.md index 83e5ad281f5..61fa59da99e 100644 --- a/topics/appendix/tools/intellij_platform_gradle_plugin/tools_intellij_platform_gradle_plugin_dependencies_extension.md +++ b/topics/appendix/tools/intellij_platform_gradle_plugin/tools_intellij_platform_gradle_plugin_dependencies_extension.md @@ -1,4 +1,4 @@ - + # Dependencies Extension @@ -19,7 +19,7 @@ It also includes methods for adding [plugins](#plugins) (including bundled), [Je **Example:** - setup Maven Central and [`defaultRepositories()`](tools_intellij_platform_gradle_plugin_repositories_extension.md#default-repositories) -- target IntelliJ IDEA Community %ijPlatform% +- target IntelliJ IDEA %ijPlatform% - add dependency on the bundled Java plugin - add IntelliJ Plugin Verifier, Marketplace ZIP Signer CLI, and code instrumentation tools - add JUnit4 test dependency @@ -41,7 +41,7 @@ repositories { dependencies { intellijPlatform { - intellijIdeaCommunity("%ijPlatform%") + intellijIdea("%ijPlatform%") bundledPlugin("com.intellij.java") @@ -69,7 +69,7 @@ repositories { dependencies { intellijPlatform { - intellijIdeaCommunity '%ijPlatform%' + intellijIdea '%ijPlatform%' bundledPlugin 'com.intellij.java' @@ -95,37 +95,58 @@ dependencies { See [](#custom-target-platforms) for non-default targets. -| Function | Description | -|-------------------------------------------------------|------------------------------------------------------------------| -| `androidStudio(version, useInstaller = true)` | [Android Studio](android_studio.md) | -| `clion(version, useInstaller = true)` | [CLion](clion.md) | -| `datagrip(version, useInstaller = true)` | [DataGrip](data_grip.md) | -| `dataspell(version, useInstaller = true)` | [DataSpell](https://www.jetbrains.com/dataspell/) | -| `fleetBackend(version, useInstaller = true)` | [Fleet](https://www.jetbrains.com/fleet/) Backend | -| `gateway(version, useInstaller = true)` | [Gateway](https://www.jetbrains.com/remote-development/gateway/) | -| `goland(version, useInstaller = true)` | [GoLand](goland.md) | -| `intellijIdeaCommunity(version, useInstaller = true)` | [IntelliJ IDEA Community](idea.md) | -| `intellijIdeaUltimate(version, useInstaller = true)` | [IntelliJ IDEA Ultimate](idea_ultimate.md) | -| `mps(version, useInstaller = true)` | [MPS](https://www.jetbrains.com/mps/) | -| `phpstorm(version, useInstaller = true)` | [PhpStorm](phpstorm.md) | -| `pycharmCommunity(version, useInstaller = true)` | [PyCharm Community](pycharm.md) | -| `pycharmProfessional(version, useInstaller = true)` | [PyCharm Professional](pycharm.md) | -| `rider(version, useInstaller = true)` | [Rider](rider.md) | -| `rubymine(version, useInstaller = true)` | [RubyMine](rubymine.md) | -| `rustrover(version, useInstaller = true)` | [RustRover](https://www.jetbrains.com/rust/) | -| `webstorm(version, useInstaller = true)` | [WebStorm](webstorm.md) | +| Function | Description | +|------------------------------------------|------------------------------------------------------------------| +| `androidStudio(version, configure = {})` | [Android Studio](android_studio.md) | +| `clion(version, configure = {})` | [CLion](clion.md) | +| `datagrip(version, configure = {})` | [DataGrip](data_grip.md) | +| `dataspell(version, configure = {})` | [DataSpell](https://www.jetbrains.com/dataspell/) | +| `fleetBackend(version, configure = {})` | [Fleet](https://www.jetbrains.com/fleet/) Backend | +| `gateway(version, configure = {})` | [Gateway](https://www.jetbrains.com/remote-development/gateway/) | +| `goland(version, configure = {})` | [GoLand](goland.md) | +| `intellijIdea(version, configure = {})` | [IntelliJ IDEA Ultimate](idea_ultimate.md) | +| `mps(version, configure = {})` | [MPS](https://www.jetbrains.com/mps/) | +| `phpstorm(version, configure = {})` | [PhpStorm](phpstorm.md) | +| `pycharm(version, configure = {})` | [PyCharm Professional](pycharm.md) | +| `rider(version, configure = {})` | [Rider](rider.md) | +| `rubymine(version, configure = {})` | [RubyMine](rubymine.md) | +| `rustRover(version, configure = {})` | [RustRover](https://www.jetbrains.com/rust/) | +| `webstorm(version, configure = {})` | [WebStorm](webstorm.md) | + +Notes: +- Writerside (`WRS`) is deprecated and no longer available as a target IntelliJ Platform. +- Aqua (`QA`) has been removed as a target IntelliJ Platform. +- IntelliJ IDEA Community (`IC`) has been removed as a target IntelliJ Platform. +- PyCharm Community (`PC`) has been removed as a target IntelliJ Platform. ### Custom Target Platforms -| Function | Description | -|----------------------------------------------|--------------------------------------------------------------------------------------------------------------------------------------------| -| `create(type, version, useInstaller = true)` | Adds a configurable dependency on the IntelliJ Platform. See [](tools_intellij_platform_gradle_plugin.md#dependenciesParametrizePlatform). | -| `create(notation, useInstaller = true)` | Adds a configurable dependency on the IntelliJ Platform. See [](tools_intellij_platform_gradle_plugin.md#dependenciesParametrizePlatform). | -| `local(localPath)` | Adds a dependency on a local IntelliJ Platform instance. See [](tools_intellij_platform_gradle_plugin.md#dependenciesLocalPlatform). | +| Function | Description | +|-----------------------------------------|--------------------------------------------------------------------------------------------------------------------------------------------| +| `create(type, version, configure = {})` | Adds a configurable dependency on the IntelliJ Platform. See [](tools_intellij_platform_gradle_plugin.md#dependenciesParametrizePlatform). | +| `create(notation, configure = {})` | Adds a configurable dependency on the IntelliJ Platform. See [](tools_intellij_platform_gradle_plugin.md#dependenciesParametrizePlatform). | +| `local(localPath)` | Adds a dependency on a local IntelliJ Platform instance. See [](tools_intellij_platform_gradle_plugin.md#dependenciesLocalPlatform). | + +### Dependency Configuration Parameters + +The last argument passed to the dependency helpers is a `configure` closure that allows to configure the dependency. +It allows you to specify the following parameters: + +| Parameter | Type | Description | +|---------------------|------------------------|-------------------------------------------------------------------------------------------------------------------------------------| +| `type` | `IntelliJPlatformType` | The type of the IntelliJ Platform dependency (target product). | +| `version` | `String` | The version of the IntelliJ Platform dependency. | +| `productMode` | `ProductMode` | Describes a mode in which a product may be started. Default: `ProductMode.MONOLITH`. | +| `useInstaller` | `Boolean` | Switches between resolving the IDE installer and a multi-OS archive from the IntelliJ Maven repository. Default: `true`. | +| `useCache` | `Boolean` | Switches between the Gradle cache and a custom cache directory. Default: `false`. See `GradleProperties.IntellijPlatformIdesCache`. | +| `configurationName` | `String` | The name of the configuration to add the dependency to. Default: `Configurations.INTELLIJ_PLATFORM_DEPENDENCY_ARCHIVE`. | + +All of the above parameters support assignment of direct values and Provider instances. See also: - [Types: `IntelliJPlatformType`](tools_intellij_platform_gradle_plugin_types.md#IntelliJPlatformType) +- [Types: `ProductMode`](tools_intellij_platform_gradle_plugin_types.md#ProductMode) ## Target Versions @@ -154,9 +175,9 @@ repositories { dependencies { intellijPlatform { - intellijIdeaCommunity("%ijPlatform%") + intellijIdea("%ijPlatform%") } - +} ``` @@ -171,7 +192,7 @@ repositories { dependencies { intellijPlatform { - intellijIdeaCommunity '%ijPlatform%' + intellijIdea '%ijPlatform%' } } ``` @@ -206,7 +227,7 @@ repositories { dependencies { intellijPlatform { - intellijIdeaCommunity("%ijPlatform%", useInstaller = false) + intellijIdea("%ijPlatform%", useInstaller = false) } } ``` @@ -223,7 +244,7 @@ repositories { dependencies { intellijPlatform { - intellijIdeaCommunity "%ijPlatform%", false + intellijIdea "%ijPlatform%", false } } ``` @@ -254,34 +275,78 @@ See also: ### Bundled Plugin -Use `bundledPlugin(id)` or `bundledPlugins(ids)` to add a dependency on bundled plugin. +Use `bundledPlugin(id)` or `bundledPlugins(ids)` to add a dependency on the bundled plugin within the currently targeted IntelliJ Platform. The list of bundled plugin IDs is available via [`printBundledPlugins`](tools_intellij_platform_gradle_plugin_tasks.md#printBundledPlugins) task. +| Function | Description | +|-----------------------|------------------------------------------------| +| `bundledPlugin(id)` | Adds a dependency on a bundled plugin. | +| `bundledPlugins(ids)` | Adds a dependency on multiple bundled plugins. | + +### Bundled Modules + +Use `bundledModule(id)` or `bundledModules(ids)` to add a dependency on an IntelliJ Platform bundled module. +This is useful when a specific platform module is required on the classpath. + +| Function | Description | +|-----------------------|------------------------------------------------| +| `bundledModule(id)` | Adds a dependency on a bundled module. | +| `bundledModules(ids)` | Adds a dependency on multiple bundled modules. | + ### Non-Bundled Plugin -Use `plugin(notation)` or `plugin(notations)` to add a dependency on a non-bundled plugin (for example, hosted on [JetBrains Marketplace](https://plugins.jetbrains.com)). +Use `plugin(notation)` or `plugins(notations)` to add a dependency on a non-bundled plugin (for example, hosted on [JetBrains Marketplace](https://plugins.jetbrains.com)). Parameter `notation` uses the following format: - `pluginId:version` or - `pluginId:version@channel`. -Alternatively, use `plugin(id, version, group)` where the `group` parameter can define a plugin release channel, like `@eap` or a full Maven coordinates group. -It is set by default to the common [JetBrains Marketplace](https://plugins.jetbrains.com) plugin artifacts group `com.jetbrains.plugins`. +Alternatively, use: +- `plugin(id, version, group)` – where `group` may define a release channel, like `@eap`, or a full Maven coordinates group (defaults to `com.jetbrains.plugins`). +- `plugins(vararg notations)` / `plugins(List)` – for multiple plugins. The `group` parameter can also describe the release channel by prefixing the value with `@` character, like `@eap` or `@nightly`. The channel value is used to prepend the JetBrains Marketplace group and build `nightly.com.jetbrains.plugins`. If defined explicitly, can be used along with any custom plugin repository, like `org.acme.plugins`. +| Function | Description | +|------------------------------|----------------------------------------| +| `plugin(id, version, group)` | Adds a dependency on a plugin. | +| `plugin(notation)` | Adds a dependency on a plugin. | +| `plugins(notations)` | Adds a dependency on multiple plugins. | + +### Compatible Plugins + +Helpers that automatically pick a version compatible with the currently configured IntelliJ Platform by requesting the JetBrains Marketplace API. + +These resolve plugin versions against the target platform configured via this extension. +Make sure the required [plugin repositories](tools_intellij_platform_gradle_plugin_repositories_extension.md#plugin-repositories) are defined. + +| Function | Description | +|--------------------------|---------------------------------------------------| +| `compatiblePlugin(id)` | Adds a dependency on a compatible plugin. | +| `compatiblePlugins(ids)` | Adds a dependency on multiple compatible plugins. | + ### Multi-Module Setup -When working on a multi-module project, use `pluginModule(dependency)` to add a dependency on a plugin module to be bundled within the main plugin JAR. -Requires passing an existing dependency, like `pluginModule(implementation(project(":submodule")))`. +When working on a multi-module project, use `pluginComposedModule(dependency)` to add a dependency on a plugin module to be bundled within the main plugin JAR. +This will produce a single plugin Jar file with all submodules' classes composed: + +```kotlin +pluginComposedModule(implementation(project(":submodule"))) +``` + +In order to use the plugin model v2, use the `pluginModule(dependency)` instead, which will move the submodule's jar into the `lib/modules/` subdirectory. + +```kotlin +pluginModule(implementation(project(":submodule"))) +``` ### Local Plugin -Use `localPlugin(localPath)` to add a dependency on a local IntelliJ Platform plugin. Accepts path or a dependency on another module. +Use `localPlugin(localPath)` to add a dependency on a local IntelliJ Platform plugin. ## Testing @@ -343,15 +408,31 @@ See also: - [Types: `TestFrameworkType`](tools_intellij_platform_gradle_plugin_types.md#TestFrameworkType) +### Test-scope plugin and module helpers + +The extension also provides helpers to add dependencies needed only for tests: + +| Function | Description | +|----------------------------------|-----------------------------------------------------------------------------------------------------------------| +| `testPlugin(notation)` | Adds a test dependency on a non-bundled plugin using `pluginId:version` or `pluginId:version@channel` notation. | +| `testPlugins(vararg notations)` | Adds test dependencies on multiple non-bundled plugins. | +| `testBundledPlugin(id)` | Adds a test dependency on a bundled plugin by ID. | +| `testBundledPlugins(vararg ids)` | Adds test dependencies on multiple bundled plugins by IDs. | +| `testLocalPlugin(localPath)` | Adds a test dependency on a local plugin; accepts a path or a project dependency. | +| `testBundledModule(id)` | Adds a test dependency on a specific bundled platform module. | +| `testBundledModules(vararg ids)` | Adds test dependencies on multiple bundled platform modules. | + +Provider and list-based overloads are available for the above helpers, mirroring their production-scope counterparts. + ## Tools -| Function | Description | -|------------------------------------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| -| `pluginVerifier(version)` | Adds a dependency on [IntelliJ Plugin Verifier](verifying_plugin_compatibility.md). Applied by default and refers to the latest available tool's version. | -| `zipSigner(version)` | Adds a dependency on [Marketplace ZIP Signer](plugin_signing.md). Applied by default and refers to the latest available tool's version. | -| `bundledLibrary(path)` | **SEE NOTE BELOW**

    Adds a dependency on a bundled library JAR file of the current IntelliJ Platform, like lib/annotations.jar.

    | -| `platformDependency(coordinates, version)` | Adds a dependency on a custom IntelliJ Platform dependency available in the [](tools_intellij_platform_gradle_plugin_repositories_extension.md#intellij-maven-repositories). | -| `testPlatformDependency(coordinates, version)` | Adds a test dependency on a custom IntelliJ Platform dependency available in the [](tools_intellij_platform_gradle_plugin_repositories_extension.md#intellij-maven-repositories). | +| Function | Description | +|------------------------------------------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| `pluginVerifier(version)` | Adds a dependency on [IntelliJ Plugin Verifier](verifying_plugin_compatibility.md). Applied by default and refers to the latest available tool's version. | +| `zipSigner(version)` | Adds a dependency on [Marketplace ZIP Signer](plugin_signing.md). Applied by default and refers to the latest available tool's version. | +| `bundledLibrary(path)` | **SEE NOTE BELOW**

    Adds a dependency on a bundled library JAR file of the current IntelliJ Platform, like lib/annotations.jar.

    | +| `platformDependency(coordinates, version)` | Adds a dependency on a custom IntelliJ Platform dependency available in the [](tools_intellij_platform_gradle_plugin_repositories_extension.md#intellij-maven-repositories). If version is omitted, the closest compatible version is used. | +| `testPlatformDependency(coordinates, version)` | Adds a test dependency on a custom IntelliJ Platform dependency available in the [](tools_intellij_platform_gradle_plugin_repositories_extension.md#intellij-maven-repositories). If version is omitted, the closest compatible version is used. | > Do not use **`bundledLibrary()`** in production, as direct access to the IntelliJ Platform libraries is not recommended. > @@ -383,7 +464,7 @@ See [](tools_intellij_platform_gradle_plugin_jetbrains_runtime.md) for more deta ## Code Instrumentation The code instrumentation process handled with the [`instrumentCode`](tools_intellij_platform_gradle_plugin_tasks.md#instrumentCode) task, requires extra dependencies to work and properly adjust the Java bytecode. -There's the `instrumentationTools()` dependencies helper introduced to apply all required dependencies using default configuration, however, it is possible to add and configure them separately. +There used to be an `instrumentationTools()` convenience helper that applied the required dependencies using defaults; it is now deprecated and calling it is no longer necessary. You can still add and configure the dependencies separately if needed. Adds a Java Compiler dependency for code instrumentation. The version is determined by the IntelliJ Platform build number. @@ -391,10 +472,10 @@ If the exact version is unavailable, the closest one is used, found by scanning The `javaCompiler()` helper is applied by default and refers to the tool version close to the currently used IntelliJ Platform. -| Function | Description | -|-------------------------------------------------------|------------------------------------------------------------------------| -|

    `instrumentationTools()`

    | A helper function to apply all required dependencies: `javaCompiler()` | -|

    `javaCompiler()`

    `javaCompiler(version)`

    | Adds a dependency on Java Compiler. | +| Function | Description | +|-------------------------------------------------------|---------------------------------------------------------------------------------------------| +|

    `instrumentationTools()`

    | Deprecated: calling this helper is no longer necessary; previously applied `javaCompiler()`. | +|

    `javaCompiler()`

    `javaCompiler(version)`

    | Adds a dependency on Java Compiler. | - [](tools_intellij_platform_gradle_plugin_tasks.md#instrumentCode) diff --git a/topics/appendix/tools/intellij_platform_gradle_plugin/tools_intellij_platform_gradle_plugin_extension.md b/topics/appendix/tools/intellij_platform_gradle_plugin/tools_intellij_platform_gradle_plugin_extension.md index 8f6dc155f92..f3760e72919 100644 --- a/topics/appendix/tools/intellij_platform_gradle_plugin/tools_intellij_platform_gradle_plugin_extension.md +++ b/topics/appendix/tools/intellij_platform_gradle_plugin/tools_intellij_platform_gradle_plugin_extension.md @@ -72,28 +72,6 @@ intellijPlatform { -### `cachePath` -{#intellijPlatform-cachePath} - -Provides read-only access to the IntelliJ Platform project cache location. - -The IntelliJ Platform cache is used for storing IntelliJ Platform Gradle Plugin-specific files, such as: -- XML files generated for the [`localPlatformArtifacts()`](tools_intellij_platform_gradle_plugin_repositories_extension.md#additional-repositories) local Ivy repository -- coroutines Java agent file created by the [`initializeIntelliJPlatformPlugin`](tools_intellij_platform_gradle_plugin_tasks.md#initializeIntelliJPlatformPlugin) task - -This path can be changed with the [`org.jetbrains.intellij.platform.intellijPlatformCache`](tools_intellij_platform_gradle_plugin_gradle_properties.md#intellijPlatformCache) Gradle property - -{type="narrow"} -Access -: Read-only - -Type -: `Path` - -Default value -: [rootProject]/.intellijPlatform/ - - ### `platformPath` {#intellijPlatform-platformPath} @@ -783,6 +761,166 @@ See also: - [Tasks: `patchPluginXml.vendorUrl`](tools_intellij_platform_gradle_plugin_tasks.md#patchPluginXml-vendorUrl) + +## Caching +{#intellijPlatform-caching} + +Configures caching related to resolving IntelliJ Platform dependencies and storing plugin-generated artifacts. + +The caching extension provides: +- Project cache path used by the IntelliJ Platform Gradle Plugin. +- IDEs sub-extension to control caching of downloaded IDEs (enable/disable, storage path, IDE directories naming). + +Example: + + + + +```kotlin +intellijPlatform { + // ... + + caching { + // Root cache used by the plugin for project-specific files + // path = layout.projectDirectory.dir(".intellijPlatform") // custom example + + ides { + enabled.set(true) + // path = layout.buildDirectory.dir("ides-cache") + // Customize directory name for a resolved IDE + name.set { requested -> "${'$'}{requested.type.code}-${'$'}{requested.version}" } + } + } +} +``` + + + + +```groovy +intellijPlatform { + // ... + + caching { + // Root cache used by the plugin for project-specific files + // path = layout.projectDirectory.dir('.intellijPlatform') // custom example + + ides { + enabled = true + // path = layout.buildDirectory.dir('ides-cache') + // Customize directory name for a resolved IDE + name = { requested -> "${'$'}{requested.type.code}-${'$'}{requested.version}" } + } + } +} +``` + + + + + + +### `path` +{#intellijPlatform-caching-path} + +Provides read-only access to the IntelliJ Platform project cache location. + +The IntelliJ Platform cache is used for storing IntelliJ Platform Gradle Plugin-specific files, such as: +- XML files generated for the [`localPlatformArtifacts()`](tools_intellij_platform_gradle_plugin_repositories_extension.md#additional-repositories) local Ivy repository +- coroutines Java agent file created by the [`initializeIntelliJPlatformPlugin`](tools_intellij_platform_gradle_plugin_tasks.md#initializeIntelliJPlatformPlugin) task +- extracted IntelliJ Platform archives instead of using Gradle cache + +This path can be changed with the [`org.jetbrains.intellij.platform.intellijPlatformCache`](tools_intellij_platform_gradle_plugin_gradle_properties.md#intellijPlatformCache) Gradle property + +{type="narrow"} +Access +: Read-only + +Type +: `Path` + +Default value +: [rootProject]/.intellijPlatform/ + + +## Caching IDEs +{#intellijPlatform-caching-ides} + +Controls caching of IntelliJ Platform IDE distributions downloaded by the plugin. + +Example: + + + + +```kotlin +intellijPlatform.caching.ides { + enabled = false + path = layout.projectDirectory.dir(".intellijPlatform/ides") + name = { requested -> "${'$'}{requested.type}-${'$'}{requested.version}" } +} +``` + + + + +```groovy +intellijPlatform.caching.ides { + enabled = false + path = layout.projectDirectory.dir('.intellijPlatform/ides') + name = { requested -> "${'$'}{requested.type}-${'$'}{requested.version}" } +} +``` + + + + + +#### `enabled` +{#intellijPlatform-caching-ides-enabled} + +Indicates whether caching for IntelliJ Platform IDEs is enabled globally. + +{type="narrow"} +Type +: `Property` + +Default value +: `false` + + +#### `path` +{#intellijPlatform-caching-ides-path} + +The cache root directory for storing downloaded IDEs. + +{type="narrow"} +Type +: `DirectoryProperty` + +Default value +:: [rootProject]/.intellijPlatform/ides/ + +See also: +- [Gradle Property: `intellijPlatformIdesCache`](tools_intellij_platform_gradle_plugin_gradle_properties.md#intellijPlatformIdesCache) + + +#### `name` +{#intellijPlatform-caching-ides-name} + +Function that returns a cache directory name for a given requested IntelliJ Platform artifact. + +{type="narrow"} +Type +: `Property<(RequestedIntelliJPlatform) -> String>` + +Default value +: `$type-$version` + +See also: +- [Types: `RequestedIntelliJPlatform`](tools_intellij_platform_gradle_plugin_types.md#RequestedIntelliJPlatform) + + ## Publishing {#intellijPlatform-publishing} @@ -1151,8 +1289,6 @@ Requires the [](tools_intellij_platform_gradle_plugin_plugins.md#platform) plugi ```kotlin -import org.jetbrains.intellij.platform.gradle.tasks.VerifyPluginTask - intellijPlatform { // ... @@ -1396,9 +1532,6 @@ It provides a set of helpers which add relevant entries to the configuration, wh ```kotlin -import org.jetbrains.intellij.platform.gradle.IntelliJPlatformType -import org.jetbrains.intellij.platform.gradle.models.ProductRelease - intellijPlatform { // ... @@ -1406,7 +1539,7 @@ intellijPlatform { // ... ides { - ide(IntelliJPlatformType.RustRover, "2023.3") + create(IntelliJPlatformType.RustRover, "2023.3") local(file("/path/to/ide/")) recommended() select { @@ -1434,7 +1567,7 @@ intellijPlatform { // ... ides { - ide IntelliJPlatformType.RustRover, "2023.3" + create IntelliJPlatformType.RustRover, "2023.3" local file('/path/to/ide/') recommended() select { @@ -1459,12 +1592,12 @@ See also: - [Types: `ProductRelease.Channel`](tools_intellij_platform_gradle_plugin_types.md#ProductRelease-Channel) - [Types: `ProductReleasesValueSource.FilterParameters`](tools_intellij_platform_gradle_plugin_types.md#ProductReleasesValueSource-FilterParameters) -| Function | Description | -|-----------------------------------------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| -|

    `ide(type, version)`

    `ide(definition)`

    | Adds a dependency to a binary IDE release to be used for testing with the IntelliJ Plugin Verifier. | -| `local(localPath)` | Adds the local IDE to be used for testing with the IntelliJ Plugin Verifier. | -| `recommended()` | Retrieves matching IDEs using the default configuration based on the currently used IntelliJ Platform and applies them for IntelliJ Platform Verifier using the `ide` helper method. | -| `select(configure)` | Retrieves matching IDEs using custom [`ProductReleasesValueSource.FilterParameters`](tools_intellij_platform_gradle_plugin_types.md#ProductReleasesValueSource-FilterParameters) filter parameters. | +| Function | Description | +|---------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| `create(...)` |

    Adds a dependency to a binary IDE release to be used for testing with the IntelliJ Plugin Verifier.

    In IntelliJ Platform Gradle Plugin older than 2.7.0, use `ide(...)`.

    | +| `local(localPath)` | Adds the local IDE to be used for testing with the IntelliJ Plugin Verifier. | +| `recommended()` | Retrieves matching IDEs using the default configuration based on the currently used IntelliJ Platform and applies them for IntelliJ Platform Verifier using the `ide` helper method. | +| `select(configure)` | Retrieves matching IDEs using custom [`ProductReleasesValueSource.FilterParameters`](tools_intellij_platform_gradle_plugin_types.md#ProductReleasesValueSource-FilterParameters) filter parameters. | diff --git a/topics/appendix/tools/intellij_platform_gradle_plugin/tools_intellij_platform_gradle_plugin_faq.md b/topics/appendix/tools/intellij_platform_gradle_plugin/tools_intellij_platform_gradle_plugin_faq.md index c89af00174a..d9aebd4d913 100644 --- a/topics/appendix/tools/intellij_platform_gradle_plugin/tools_intellij_platform_gradle_plugin_faq.md +++ b/topics/appendix/tools/intellij_platform_gradle_plugin/tools_intellij_platform_gradle_plugin_faq.md @@ -358,7 +358,7 @@ import org.jetbrains.intellij.platform.gradle.models.ProductRelease tasks { printProductsReleases { channels = listOf(ProductRelease.Channel.EAP) - types = listOf(IntelliJPlatformType.IntellijIdeaCommunity) + types = listOf(IntelliJPlatformType.IntellijIdea) untilBuild = provider { null } doLast { @@ -378,7 +378,7 @@ import org.jetbrains.intellij.platform.gradle.models.ProductRelease tasks { printProductsReleases { channels = [ProductRelease.Channel.EAP] - types = [IntelliJPlatformType.IntellijIdeaCommunity] + types = [IntelliJPlatformType.IntellijIdea] untilBuild = null doLast { @@ -464,7 +464,7 @@ To correctly run your tests or a specific IDE: dependencies { intellijPlatform { - intellijIdeaCommunity("%ijPlatform%") + intellijIdea("%ijPlatform%") jetbrainsRuntime("...") } } @@ -485,7 +485,7 @@ To correctly run your tests or a specific IDE: dependencies { intellijPlatform { - intellijIdeaCommunity '%ijPlatform%' + intellijIdea '%ijPlatform%' jetbrainsRuntime '...' } } diff --git a/topics/appendix/tools/intellij_platform_gradle_plugin/tools_intellij_platform_gradle_plugin_gradle_properties.md b/topics/appendix/tools/intellij_platform_gradle_plugin/tools_intellij_platform_gradle_plugin_gradle_properties.md index 63b548a4ccd..e217cf6e36a 100644 --- a/topics/appendix/tools/intellij_platform_gradle_plugin/tools_intellij_platform_gradle_plugin_gradle_properties.md +++ b/topics/appendix/tools/intellij_platform_gradle_plugin/tools_intellij_platform_gradle_plugin_gradle_properties.md @@ -199,3 +199,71 @@ Example ``` org.jetbrains.intellij.platform.useCacheRedirector=false ``` + + +## `addDefaultIntellijPlatformDependencies` +{#addDefaultIntellijPlatformDependencies} + +Controls whether default IntelliJ Platform repositories and coordinates (like `com.intellij` and `intellij.rider`) should be added automatically when creating a dependency on the IntelliJ Platform. + +{type="narrow"} +Default value +: `true` + +Example +: +``` +org.jetbrains.intellij.platform.addDefaultIntellijPlatformDependencies=false +``` + + +## `intellijPlatformIdesCache` +{#intellijPlatformIdesCache} + +Specifies the location of the cache directory for storing downloaded IDE distributions and related artifacts. +This cache can be shared between multiple projects and is used when IDE caching is enabled. + +See also: +- [Extension: `intellijPlatform.caching.ides`](tools_intellij_platform_gradle_plugin_extension.md#intellijPlatform-caching-ides) + +{type="narrow"} +Default value +: [`intellijPlatformCache`](#intellijPlatformCache)/ides/ + +Example +: +``` +org.jetbrains.intellij.platform.intellijPlatformIdesCache=/path/to/ides-cache/ +``` + + +## `productsReleasesCdnBuildsUrl` +{#productsReleasesCdnBuildsUrl} + +Specifies the URL from which the list of JetBrains IDE CDN release builds is fetched. This listing is used for mapping IDE releases to build numbers (for example, to download the corresponding JetBrains Client archive). + +{type="narrow"} +Default value +: `https://data.services.jetbrains.com/products/releases?type=release` + +Example +: +``` +org.jetbrains.intellij.platform.productsReleasesCdnBuildsUrl=https://... +``` + + +## `verifyPluginProjectConfigurationMutedMessages` +{#verifyPluginProjectConfigurationMutedMessages} + +Allows muting specific messages reported by the [`verifyPluginProjectConfiguration`](tools_intellij_platform_gradle_plugin_tasks.md#verifyPluginProjectConfiguration) task. The property accepts a comma-separated list of message patterns. Each pattern is matched against the message text using a case-sensitive substring search. + +{type="narrow"} +Default value +: empty (no messages are muted) + +Example +: +``` +org.jetbrains.intellij.platform.verifyPluginProjectConfigurationMutedMessages=Kotlin Standard Library,Java Runtime is not JetBrains Runtime +``` diff --git a/topics/appendix/tools/intellij_platform_gradle_plugin/tools_intellij_platform_gradle_plugin_jetbrains_runtime.md b/topics/appendix/tools/intellij_platform_gradle_plugin/tools_intellij_platform_gradle_plugin_jetbrains_runtime.md index 5b8313ce82a..e4896898c1b 100644 --- a/topics/appendix/tools/intellij_platform_gradle_plugin/tools_intellij_platform_gradle_plugin_jetbrains_runtime.md +++ b/topics/appendix/tools/intellij_platform_gradle_plugin/tools_intellij_platform_gradle_plugin_jetbrains_runtime.md @@ -42,7 +42,7 @@ repositories { dependencies { intellijPlatform { - intellijIdeaCommunity("%ijPlatform%") + intellijIdea("%ijPlatform%") jetbrainsRuntime() @@ -66,7 +66,7 @@ repositories { dependencies { intellijPlatform { - intellijIdeaCommunity '%ijPlatform%' + intellijIdea '%ijPlatform%' jetbrainsRuntime() @@ -78,6 +78,7 @@ dependencies {
    +**Note:** As of version `2.2.0` of the IntelliJ Platform Gradle Plugin, explicitly specifying `jetbrainsRuntime()` in the `repositories` block is no longer necessary if you also have `defaultRepositories()` specified. ## Declared Explicitly @@ -98,7 +99,7 @@ repositories { dependencies { intellijPlatform { - intellijIdeaCommunity("%ijPlatform%") + intellijIdea("%ijPlatform%") jetbrainsRuntime(version, variant, architecture) // or @@ -124,7 +125,7 @@ repositories { dependencies { intellijPlatform { - intellijIdeaCommunity '%ijPlatform%' + intellijIdea '%ijPlatform%' jetbrainsRuntime(version, variant, architecture) // or @@ -138,6 +139,7 @@ dependencies {
    +**Note:** As of version `2.2.0` of the IntelliJ Platform Gradle Plugin, explicitly specifying `jetbrainsRuntime()` in the `repositories` block is no longer necessary if you also have `defaultRepositories()` specified. Provided `version`, `variant`, and `architecture` parameters along with the `explicitVersion` are used to resolve the JetBrains Runtime archives published on [GitHub Releases](https://github.com/JetBrains/JetBrainsRuntime/releases/) page. diff --git a/topics/appendix/tools/intellij_platform_gradle_plugin/tools_intellij_platform_gradle_plugin_plugins.md b/topics/appendix/tools/intellij_platform_gradle_plugin/tools_intellij_platform_gradle_plugin_plugins.md index bd371f698f2..f131ff2659b 100644 --- a/topics/appendix/tools/intellij_platform_gradle_plugin/tools_intellij_platform_gradle_plugin_plugins.md +++ b/topics/appendix/tools/intellij_platform_gradle_plugin/tools_intellij_platform_gradle_plugin_plugins.md @@ -147,7 +147,7 @@ repositories { dependencies { intellijPlatform { - intellijIdeaCommunity("%ijPlatform%") + intellijIdea("%ijPlatform%") } } ``` @@ -169,7 +169,7 @@ repositories { dependencies { intellijPlatform { - intellijIdeaCommunity("%ijPlatform%") + intellijIdea("%ijPlatform%") pluginModule(implementation(project(":submodule"))) } } @@ -203,7 +203,7 @@ repositories { dependencies { intellijPlatform { - intellijIdeaCommunity '%ijPlatform%' + intellijIdea '%ijPlatform%' } } ``` @@ -225,7 +225,7 @@ repositories { dependencies { intellijPlatform { - intellijIdeaCommunity '%ijPlatform%' + intellijIdea '%ijPlatform%' pluginModule(implementation(project(':submodule'))) } } @@ -304,7 +304,7 @@ plugins { dependencies { intellijPlatform { - intellijIdeaCommunity("%ijPlatform%") + intellijIdea("%ijPlatform%") pluginModule(implementation(project(":submodule"))) } } @@ -325,7 +325,7 @@ plugins { dependencies { intellijPlatform { - intellijIdeaCommunity("%ijPlatform%") + intellijIdea("%ijPlatform%") } } ``` @@ -368,7 +368,7 @@ plugins { dependencies { intellijPlatform { - intellijIdeaCommunity '%ijPlatform%' + intellijIdea '%ijPlatform%' pluginModule(implementation(project(':submodule'))) } } @@ -389,7 +389,7 @@ plugins { dependencies { intellijPlatform { - intellijIdeaCommunity '%ijPlatform%' + intellijIdea '%ijPlatform%' } } ``` diff --git a/topics/appendix/tools/intellij_platform_gradle_plugin/tools_intellij_platform_gradle_plugin_repositories_extension.md b/topics/appendix/tools/intellij_platform_gradle_plugin/tools_intellij_platform_gradle_plugin_repositories_extension.md index 5802c576812..4f34235d96a 100644 --- a/topics/appendix/tools/intellij_platform_gradle_plugin/tools_intellij_platform_gradle_plugin_repositories_extension.md +++ b/topics/appendix/tools/intellij_platform_gradle_plugin/tools_intellij_platform_gradle_plugin_repositories_extension.md @@ -1,4 +1,4 @@ - + # Repositories Extension @@ -62,6 +62,7 @@ repositories { ## Default Repositories +{#default-repositories} The default repository definition is suitable for most plugins. @@ -73,6 +74,7 @@ It includes: - `jetbrainsIdeInstallers()` and `androidStudioInstallers()` – IntelliJ Platform and Android Studio installer releases channels required for development and running the IntelliJ Plugin Verifier - `releases()` and `snapshots()` – IntelliJ Platform releases channels - `localPlatformArtifacts()` – required to use plugins bundled with IntelliJ Platform or refer to a local IDE +- `jetbrainsRuntime()` – JetBrains Runtime releases - `marketplace()` – JetBrains Marketplace plugins repository - `intellijDependencies()` – required for resolving extra IntelliJ Platform dependencies used for running specific tasks @@ -166,14 +168,10 @@ repositories { The final plugin archive is eventually resolved using the same credentials used for resolving the listing. - -| Function | Description | -|-------------------------------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| -| `localPlatformArtifacts()` | Certain dependencies, such as the [local IntelliJ Platform instance](tools_intellij_platform_gradle_plugin.md#dependenciesLocalPlatform) and bundled IDE plugins, need extra pre-processing before they can be correctly used by the IntelliJ Platform Gradle Plugin and loaded by Gradle.

    This pre-processing involves generating XML files that detail these specific artifacts. Once created, these are stored in a unique custom [Ivy](https://ant.apache.org/ivy/) repository directory.

    | -| `intellijDependencies()` | Adds a repository for accessing IntelliJ Platform dependencies. | -| `jetbrainsRuntime()` | Adds a repository for accessing [JetBrains Runtime](ide_development_instance.md#using-a-jetbrains-runtime-for-the-development-instance) releases. | -| `marketplace()` | Adds a repository for accessing plugins hosted on [JetBrains Marketplace](https://plugins.jetbrains.com). | -| `customPluginRepository(url, type)` | Creates a custom plugin repository from which plugins | +| Function | Description | +|-------------------------------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| `marketplace()` | Adds a repository for accessing plugins hosted on [JetBrains Marketplace](https://plugins.jetbrains.com). | +| `customPluginRepository(url, type)` | Creates a custom plugin repository from which plugins can be resolved. Supports optional credentials (e.g., HttpHeaderCredentials). See [](custom_plugin_repository.md). | ## Additional Repositories diff --git a/topics/appendix/tools/intellij_platform_gradle_plugin/tools_intellij_platform_gradle_plugin_task_awares.md b/topics/appendix/tools/intellij_platform_gradle_plugin/tools_intellij_platform_gradle_plugin_task_awares.md index e8544e8c207..bf5c157de67 100644 --- a/topics/appendix/tools/intellij_platform_gradle_plugin/tools_intellij_platform_gradle_plugin_task_awares.md +++ b/topics/appendix/tools/intellij_platform_gradle_plugin/tools_intellij_platform_gradle_plugin_task_awares.md @@ -141,6 +141,28 @@ Type : `ConfigurableFileCollection` +### `intelliJPlatformPluginConfiguration` +{#IntelliJPlatformVersionAware-intelliJPlatformPluginConfiguration} + +Holds the `intellijPlatformPlugin` configuration with optional custom IntelliJ Platform plugin dependencies added. +It should not be directly accessed. + +{type="narrow"} +Type +:: `ConfigurableFileCollection` + + +### `intelliJPlatformTestRuntimeFixClasspathConfiguration` +{#IntelliJPlatformVersionAware-intelliJPlatformTestRuntimeFixClasspathConfiguration} + +Holds the `intellijPlatformTestRuntimeFixClasspath` configuration with the custom IntelliJ Platform core dependency required for running tests. +It should not be directly accessed. + +{type="narrow"} +Type +:: `ConfigurableFileCollection` + + ### `platformPath` {#IntelliJPlatformVersionAware-platformPath} @@ -314,6 +336,37 @@ Default value +## `ModuleAware` +{#ModuleAware} + + + +**Inherited by**: [`PluginAware`](#PluginAware) + +**Sources**: [`ModuleAware`](%gh-ijpgp%/src/main/kotlin/org/jetbrains/intellij/platform/gradle/tasks/aware/ModuleAware.kt) + + + +Provides information about whether the current task is executed in an IntelliJ Platform plugin module context. + +### `module` +{#ModuleAware-module} + +Indicates if the current project represents an IntelliJ Platform plugin module. + +{type="narrow"} +Type +:: `Property` + +Default value +:: `PluginManager.isModule` + +Notes: +- The IntelliJ Platform Gradle Plugin wires this property automatically for tasks implementing ModuleAware during task preconfiguration. +- You typically do not set this value yourself; consume it in your task to branch logic. + + + ## `PluginAware` {#PluginAware} @@ -445,7 +498,18 @@ Inherits from: -Provides access to the Java Runtime (i.e., JetBrains Runtime) resolved with `RuntimeResolver`. +Provides access to the Java Runtime (i.e., JetBrains Runtime) resolved with `JavaRuntimePathResolver`. + + +### `jetbrainsRuntimeConfiguration` +{#RuntimeAware-jetbrainsRuntimeConfiguration} + +Holds the `intellijPlatformJetbrainsRuntime` configuration with the JetBrains Runtime dependency added. +It should not be directly accessed. + +{type="narrow"} +Type +:: `ConfigurableFileCollection` ### `runtimeDirectory` @@ -475,7 +539,7 @@ Metadata object of the Java Runtime currently used for running Gradle. {type="narrow"} Type -: `Property` +:: `MapProperty` ### `runtimeLauncher` @@ -485,8 +549,76 @@ A custom `JavaLauncher` instance configured with the resolved [`runtimeDirectory {type="narrow"} Type -: `Property` +: `Property` + + +## `SandboxStructure` +{#SandboxStructure} + + + +**Inherited by**: [`SandboxAware`](#SandboxAware), [`SplitModeAware`](#SplitModeAware) + +**Sources**: [`SandboxStructure`](%gh-ijpgp%/src/main/kotlin/org/jetbrains/intellij/platform/gradle/tasks/aware/SandboxStructure.kt) + + + +Defines common sandbox directories and flags used by tasks interacting with IDE sandboxes. + +### `sandboxDirectory` +{#SandboxStructure-sandboxDirectory} + +The directory containing content read and produced by the running IDE. The directory name depends on the platform type and version currently used for running a task. + +{type="narrow"} +Type +:: `DirectoryProperty` + +### `sandboxConfigDirectory` +{#SandboxStructure-sandboxConfigDirectory} + +A configuration directory located within the [`sandboxDirectory`](#SandboxStructure-sandboxDirectory). + +{type="narrow"} +Type +:: `DirectoryProperty` + +### `sandboxPluginsDirectory` +{#SandboxStructure-sandboxPluginsDirectory} + +A plugins directory located within the [`sandboxDirectory`](#SandboxStructure-sandboxDirectory). + +{type="narrow"} +Type +:: `DirectoryProperty` + +### `sandboxSystemDirectory` +{#SandboxStructure-sandboxSystemDirectory} + +A system directory located within the [`sandboxDirectory`](#SandboxStructure-sandboxDirectory). + +{type="narrow"} +Type +:: `DirectoryProperty` + +### `sandboxLogDirectory` +{#SandboxStructure-sandboxLogDirectory} + +A log directory located within the [`sandboxDirectory`](#SandboxStructure-sandboxDirectory). + +{type="narrow"} +Type +:: `DirectoryProperty` + +### `testSandbox` +{#SandboxStructure-testSandbox} + +Defines if the current sandbox is related to testing. + +{type="narrow"} +Type +:: `Property` ## `SandboxAware` diff --git a/topics/appendix/tools/intellij_platform_gradle_plugin/tools_intellij_platform_gradle_plugin_tasks.md b/topics/appendix/tools/intellij_platform_gradle_plugin/tools_intellij_platform_gradle_plugin_tasks.md index 898dd3c4aac..2c52102523c 100644 --- a/topics/appendix/tools/intellij_platform_gradle_plugin/tools_intellij_platform_gradle_plugin_tasks.md +++ b/topics/appendix/tools/intellij_platform_gradle_plugin/tools_intellij_platform_gradle_plugin_tasks.md @@ -92,7 +92,7 @@ Type : `DirectoryProperty` Default value -: [buildDirectory]/searchableOptions +:: [buildDirectory]/tmp/buildSearchableOptions ### `showPaidPluginWarning` @@ -153,9 +153,9 @@ Type **Available in:** [](tools_intellij_platform_gradle_plugin_plugins.md#platform), [](tools_intellij_platform_gradle_plugin_plugins.md#module) -**Extends**: [`DefaultTask`][gradle-default-task], [`IntelliJPlatformVersionAware`](tools_intellij_platform_gradle_plugin_task_awares.md#IntelliJPlatformVersionAware) +**Extends**: [`DefaultTask`][gradle-default-task], [`KotlinMetadataAware`](tools_intellij_platform_gradle_plugin_task_awares.md#KotlinMetadataAware) -**Sources**: [`InitializeIntelliJPlatformPluginTask`](%gh-ijpgp%/src/main/kotlin/org/jetbrains/intellij/platform/gradle/tasks/InitializeIntelliJPlatformPluginTask.kt) +**Sources**: [`GenerateManifestTask`](%gh-ijpgp%/src/main/kotlin/org/jetbrains/intellij/platform/gradle/tasks/GenerateManifestTask.kt) @@ -236,10 +236,8 @@ Executes before every other task introduced by IntelliJ Platform Gradle Plugin t It is responsible for: - checking if the project uses IntelliJ Platform Gradle Plugin in the latest available version -- preparing the KotlinX Coroutines Java Agent file to enable coroutines debugging when developing the plugin The self-update check can be disabled via [`selfUpdateCheck`](tools_intellij_platform_gradle_plugin_gradle_properties.md#selfUpdateCheck) Gradle property. -To make the Coroutines Java Agent available for the task, inherit from [`CoroutinesJavaAgentAware`](tools_intellij_platform_gradle_plugin_task_awares.md#CoroutinesJavaAgentAware). ### `offline` @@ -286,7 +284,7 @@ Type ### `coroutinesJavaAgent` {#initializeIntelliJPlatformPlugin-coroutinesJavaAgent} -Specifies the Java Agent file for the Coroutines library required to enable coroutines debugging. +Deprecated: this task no longer exposes a coroutines agent property. To enable coroutines debugging, use tasks implementing [CoroutinesJavaAgentAware](tools_intellij_platform_gradle_plugin_task_awares.md#CoroutinesJavaAgentAware) which provide `coroutinesJavaAgentFile`. {type="narrow"} Type @@ -323,7 +321,7 @@ Defines that the current project has only the [](tools_intellij_platform_gradle_ {type="narrow"} Type -: `Property` +: `Property` @@ -348,8 +346,8 @@ Executes the code instrumentation using the Ant tasks provided by the used Intel The code instrumentation scans the compiled Java and Kotlin classes for JetBrains Annotations usages to replace them with their relevant functionalities. The task is controlled with the [`intellijPlatform.instrumentCode`](tools_intellij_platform_gradle_plugin_extension.md#intellijPlatform-instrumentCode) extension property, enabled by default. -To properly run the instrumentation, it is required to add [`instrumentationTools()`](tools_intellij_platform_gradle_plugin_dependencies_extension.md#code-instrumentation) dependencies to the project. -This dependency is available via the [`intellijDependencies()`](tools_intellij_platform_gradle_plugin_repositories_extension.md#additional-repositories) repository, which can be added separately or using the [`defaultRepositories()`](tools_intellij_platform_gradle_plugin_repositories_extension.md#default-repositories) helper. +To properly run the instrumentation, a Java Compiler dependency must be available. This is applied by default by the plugin; previously, the `instrumentationTools()` helper was used, but it is now deprecated and calling it is no longer necessary. You can still add and configure the dependency manually via [`javaCompiler()`](tools_intellij_platform_gradle_plugin_dependencies_extension.md#code-instrumentation) if needed. +This dependency is resolved via the [`intellijDependencies()`](tools_intellij_platform_gradle_plugin_repositories_extension.md#additional-repositories) repository, which can be added separately or using the [`defaultRepositories()`](tools_intellij_platform_gradle_plugin_repositories_extension.md#default-repositories) helper. See also: - [](#instrumentedJar) @@ -1867,7 +1865,7 @@ Type : `Property` Default value -: [`intellijPlatform.cachePath`](tools_intellij_platform_gradle_plugin_extension.md#intellijPlatform-cachePath) +: [`intellijPlatform.cachePath`](tools_intellij_platform_gradle_plugin_extension.md#intellijPlatform-caching-path) ### `gitignoreFile` diff --git a/topics/appendix/tools/intellij_platform_gradle_plugin/tools_intellij_platform_gradle_plugin_types.md b/topics/appendix/tools/intellij_platform_gradle_plugin/tools_intellij_platform_gradle_plugin_types.md index 33a5d4080b4..c0d8de0a966 100644 --- a/topics/appendix/tools/intellij_platform_gradle_plugin/tools_intellij_platform_gradle_plugin_types.md +++ b/topics/appendix/tools/intellij_platform_gradle_plugin/tools_intellij_platform_gradle_plugin_types.md @@ -1,4 +1,4 @@ - + # Types @@ -47,26 +47,46 @@ Describes all IntelliJ Platform types available to be used for plugin developmen Each entry is composed of a product code and coordinates used for dependency and binary release resolution. -| Name | Code | Artifact Coordinates | Binary release | -|-------------------------|--------|----------------------------------------------------|:--------------:| -| `AndroidStudio` | `AI` | - | ✓ | -| `CLion` | `CL` | `com.jetbrains.intellij.clion:clion` | ✓ | -| `DataGrip` | `DB` | - | ✓ | -| `DataSpell` | `DS` | - | ✓ | -| `FleetBackend` | `FLIJ` | `com.jetbrains.intellij.fleetBackend:fleetBackend` | | -| `Gateway` | `GW` | `com.jetbrains.intellij.gateway:gateway` | ✓ | -| `GoLand` | `GO` | `com.jetbrains.intellij.goland:goland` | ✓ | -| `IntellijIdeaCommunity` | `IC` | `com.jetbrains.intellij.idea:ideaIC` | ✓ | -| `IntellijIdeaUltimate` | `IU` | `com.jetbrains.intellij.idea:ideaIU` | ✓ | -| `MPS` | `MPS` | - | ✓ | -| `PhpStorm` | `PS` | `com.jetbrains.intellij.phpstorm:phpstorm` | ✓ | -| `PyCharmProfessional` | `PY` | `com.jetbrains.intellij.pycharm:pycharmPY` | ✓ | -| `PyCharmCommunity` | `PC` | `com.jetbrains.intellij.pycharm:pycharmPC` | ✓ | -| `Rider` | `RD` | `com.jetbrains.intellij.rider:riderRD` | ✓ | -| `RubyMine` | `RM` | - | ✓ | -| `RustRover` | `RR` | `com.jetbrains.intellij.rustrover:RustRover` | ✓ | -| `WebStorm` | `WS` | `com.jetbrains.intellij.webstorm:webstorm` | ✓ | +| Name | Code | Artifact Coordinates | Binary release | +|-------------------|--------|----------------------------------------------------|:--------------:| +| `AndroidStudio` | `AI` | - | ✓ | +| `CLion` | `CL` | `com.jetbrains.intellij.clion:clion` | ✓ | +| `DataGrip` | `DB` | - | ✓ | +| `DataSpell` | `DS` | - | ✓ | +| `FleetBackend` | `FLIJ` | `com.jetbrains.intellij.fleetBackend:fleetBackend` | | +| `JetBrainsClient` | `JBC` | - | ✓ | +| `Gateway` | `GW` | `com.jetbrains.intellij.gateway:gateway` | ✓ | +| `GoLand` | `GO` | `com.jetbrains.intellij.goland:goland` | ✓ | +| `IntellijIdea ` | `IU` | `com.jetbrains.intellij.idea:ideaIU` | ✓ | +| `MPS` | `MPS` | - | ✓ | +| `PhpStorm` | `PS` | `com.jetbrains.intellij.phpstorm:phpstorm` | ✓ | +| `PyCharm` | `PY` | `com.jetbrains.intellij.pycharm:pycharmPY` | ✓ | +| `Rider` | `RD` | `com.jetbrains.intellij.rider:riderRD` | ✓ | +| `RubyMine` | `RM` | - | ✓ | +| `RustRover` | `RR` | `com.jetbrains.intellij.rustrover:RustRover` | ✓ | +| `WebStorm` | `WS` | `com.jetbrains.intellij.webstorm:webstorm` | ✓ | + +Note: +- Aqua (`QA`) and Writerside (`WRS`) are deprecated and no longer available as target IntelliJ Platform products. +- IntelliJ IDEA Community (`IC`) has been removed as a target IntelliJ Platform. +- PyCharm Community (`PC`) has been removed as a target IntelliJ Platform. + +## `ProductMode` +{#ProductMode} + +[`ProductMode`](%gh-ijpgp%/src/main/kotlin/org/jetbrains/intellij/platform/gradle/ProductMode.kt) + +Describes a mode in which a product may be started. This can be configured on the target platform dependency to influence how the IDE is started for development and testing. + +| Name | Description | +|------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| `MONOLITH` | Indicates that this process performs all necessary tasks to provide smart features itself. This is the default mode for all IDEs. | +| `FRONTEND` | Indicates that this process doesn't perform heavy tasks like code analysis, and takes necessary information from another process. Currently used by JetBrains Client connected to a remote development host or Code With Me session. | +| `BACKEND` | Indicates that this process doesn't perform heavy tasks like code analysis and takes necessary information from another process. Currently used by an IDE running as a remote development host. | +See also: +- [Dependencies Extension: Dependency Configuration Parameters](tools_intellij_platform_gradle_plugin_dependencies_extension.md#dependency-configuration-parameters) +- [Types: SplitModeAware.SplitModeTarget](tools_intellij_platform_gradle_plugin_types.md#SplitModeAware-SplitModeTarget) ## `PluginBean` {#PluginBean} @@ -95,6 +115,7 @@ See also the corresponding [`product-info.schema.json`](%gh-ic%/platform/buildDa | `versionSuffix` | The suffix of the version, like "EAP". | | `buildNumber` | The build number of the product, like "232.8660.185". | | `productCode` | The product code, like "IU". | +| `envVarBaseName` | Base name used for product-specific environment variables. | | `dataDirectoryName` | The directory name of the product data. | | `svgIconPath` | The path to the SVG icon of the product. | | `productVendor` | The vendor of the product. | @@ -162,6 +183,23 @@ See also: - [Gradle Properties: `productsReleasesJetBrainsIdesUrl`](tools_intellij_platform_gradle_plugin_gradle_properties.md#productsReleasesJetBrainsIdesUrl) +## `RequestedIntelliJPlatform` +{#RequestedIntelliJPlatform} + +[`RequestedIntelliJPlatform`](%gh-ijpgp%/src/main/kotlin/org/jetbrains/intellij/platform/gradle/services/RequestedIntelliJPlatformsService.kt) + +Represents a requested IntelliJ Platform build with its type, version, and installation/cache preferences. +Used internally by the Gradle plugin to propagate platform settings across configurations for development, dependency resolution, and plugin verification. + +| Name | Description | +|----------------|-----------------------------------------------------------------------------------| +| `type` | IntelliJ Platform type. See [`IntelliJPlatformType`](#IntelliJPlatformType). | +| `version` | Version of the IntelliJ Platform to use (for example, "2024.2", "241.15989.150"). | +| `useInstaller` | Whether the installer distribution of the platform should be used. | +| `useCache` | Whether a custom cache directory should be used when resolving the platform. | +| `productMode` | Desired product mode. See [`ProductMode`](#ProductMode). | + + ## `SplitModeAware.SplitModeTarget` {#SplitModeAware-SplitModeTarget} @@ -230,14 +268,17 @@ Generic test frameworks for the IntelliJ Platform. Some plugins offer dedicated test frameworks, for example, `Plugin.Java` when using Java/JVM-related functionality. -| Name | Coordinates | Reference | -|---------------------|---------------------------------------------------------------|-----------------| -| `Plugin.Go` | `com.jetbrains.intellij.go:go-test-framework` | [](goland.md) | -| `Plugin.JavaScript` | `com.jetbrains.intellij.javascript:javascript-test-framework` | [](webstorm.md) | -| `Plugin.Java` | `com.jetbrains.intellij.java:java-test-framework` | [](idea.md) | -| `Plugin.Maven` | `com.jetbrains.intellij.maven:maven-test-framework` | | -| `Plugin.ReSharper` | `com.jetbrains.intellij.resharper:resharper-test-framework` | [](rider.md) | -| `Plugin.Ruby` | `com.jetbrains.intellij.idea:ruby-test-framework` | [](rubymine.md) | +| Name | Coordinates | Reference | +|----------------------|---------------------------------------------------------------|-----------------| +| `Plugin.CSS` | `com.jetbrains.intellij.css:css-test-framework` | [](webstorm.md) | +| `Plugin.Go` | `com.jetbrains.intellij.go:go-test-framework` | [](goland.md) | +| `Plugin.JavaScript` | `com.jetbrains.intellij.javascript:javascript-test-framework` | [](webstorm.md) | +| `Plugin.Java` | `com.jetbrains.intellij.java:java-test-framework` | [](idea.md) | +| `Plugin.LSP` | `com.jetbrains.intellij.platform:test-lsp-framework` | | +| `Plugin.Maven` | `com.jetbrains.intellij.maven:maven-test-framework` | | +| `Plugin.ReSharper` | `com.jetbrains.intellij.resharper:resharper-test-framework` | [](rider.md) | +| `Plugin.Ruby` | `com.jetbrains.intellij.idea:ruby-test-framework` | [](rubymine.md) | +| `Plugin.XML` | `com.jetbrains.intellij.xml:xml-test-framework` | | ## `VerificationReportsFormats` {#VerificationReportsFormats} diff --git a/topics/appendix/tools/tools_kotlin_notebook.md b/topics/appendix/tools/tools_kotlin_notebook.md new file mode 100644 index 00000000000..71543ac6542 --- /dev/null +++ b/topics/appendix/tools/tools_kotlin_notebook.md @@ -0,0 +1,235 @@ + + +# Kotlin Notebook Integration + +Interactive IntelliJ Platform development using Kotlin Notebook. + + + + +**GitHub**: [Kotlin Notebook IntelliJ Platform](https://github.com/Kotlin/kotlin-notebook-intellij-platform) + +**Examples**: [Kotlin Notebook IntelliJ Platform examples](https://github.com/Kotlin/kotlin-notebook-intellij-platform/tree/master/examples) + +**JetBrains Platform Forum**: [Kotlin Notebook](https://platform.jetbrains.com/c/intellij-platform/kotlin-notebook/25) category + + + +The Kotlin Notebook IntelliJ Platform integration enables interactive development and experimentation with IntelliJ Platform APIs directly within a notebook environment. This integration allows developers to run IntelliJ Platform code within the active IDE runtime, removing traditional barriers associated with plugin project setup, compilation, and deployment. + +Like Jupyter Notebooks, Kotlin Notebook provides an interactive platform for prototyping, testing, and exploring IntelliJ Platform functionality through executable code cells. + +## Getting Started + +To begin using the IntelliJ Platform integration: + + + +1. Create a new Kotlin Notebook file (`.ipynb`) in your project or as a scratch file using ⌘⇧N on macOS or Ctrl+Shift+N on Windows/Linux. +2. **Important**: Switch to **Run in IDE Process** mode in the notebook toolbar. +3. In the first code cell, declare: + ```kotlin + %use intellij-platform + ``` + + +Once executed, the necessary IntelliJ Platform libraries are loaded into the Kotlin Notebook classpath, making them available for import in subsequent cells. + +## Core Features + +### UI Rendering + +The integration enables direct rendering of UI components within notebook cells. When working with [Kotlin UI DSL](kotlin_ui_dsl_version_2.md) or standard Swing components, returning them as a response causes immediate rendering with full interactivity. + +```kotlin +import com.intellij.ui.dsl.builder.panel +import java.awt.Dimension + +panel { + row { + checkBox("Check me!") + } +}.apply { + size = Dimension(500, 200) +} +``` + +Use the `runInEdt` helper to ensure code execution on the [Event Dispatch Thread (EDT)](threading_model.md) and handle exceptions gracefully: + +```kotlin +runInEdt { + // UI code that must run on EDT +} +``` + +### Resource Management + +The integration provides automatic resource management through the IntelliJ Platform's [Disposer](disposers.md) mechanism. A dedicated `notebookDisposable` variable allows registration of elements that need cleanup: + +```kotlin +Disposer.register(notebookDisposable, myDisposable) + +Disposer.register(notebookDisposable) { + // ... +} +``` + +### Plugin Loading + +By default, only the core IntelliJ Platform is loaded into the classpath. To use other plugins (bundled or installed), explicitly load them using: + +```kotlin +loadPlugins("Git4Idea", "com.intellij.java") +``` + +### Extension Registration + +Unlike traditional plugin development with plugin.xml, the integration provides programmatic extension registration: + +```kotlin +registerExtension(extensionPointName, instance) +``` + +## Global Variables +{id="variables"} + +When the IntelliJ Platform integration is loaded, the following variables are automatically available in your Kotlin Notebook environment. +These variables provide access to essential IDE components, configuration information, and management interfaces. + +| Variable | Type | Description | +|----------------------------|------------------------------------------------------------------------------------------------------------------------------------------------------|--------------------------------------------------------------------------------------------------------------------------------------| +| `idePath` | `Path` | Represents the resolved file system path to the IntelliJ Platform installation directory. | +| `ide` | [`ProductInfoBasedIde`](%gh-pv%/intellij-plugin-structure/structure-ide/src/main/java/com/jetbrains/plugin/structure/ide/ProductInfoBasedIde.kt) | Represents an IDE instance, which allows interacting with plugins and resolving their dependencies based on the IDE's configuration. | +| `notebookDisposable` | [`Disposable`](%gh-ic%/platform/util/src/com/intellij/openapi/Disposable.java) | Represents a disposable used for managing the IntelliJ Platform lifetime of the current notebook. | +| `notebookPluginDescriptor` | [`PluginMainDescriptor`](%gh-ic%/platform/core-impl/src/com/intellij/ide/plugins/IdeaPluginDescriptorImpl.kt) | Represents a plugin descriptor for the plugin created with Kotlin Notebook IntelliJ Platform integration. | +| `pluginManager` | [`PluginManager`](%gh-ic%/platform/core-impl/src/com/intellij/ide/plugins/PluginManager.java) | Instance of the `PluginManager`, which allows accessing information about plugins and their states in the current IDE environment. | +| `pluginRepository` | [`PluginRepository`](%gh-pv%/intellij-plugin-verifier/verifier-repository/src/main/java/com/jetbrains/pluginverifier/repository/PluginRepository.kt) | Instance of `PluginRepository`, responsible for managing plugins via the JetBrains Marketplace plugin repository. | +| `productInfo` | [`ProductInfo`](%gh-pv%/intellij-plugin-structure/structure-intellij/src/main/java/com/jetbrains/plugin/structure/intellij/platform/ProductInfo.kt) | Lazily initialized property containing current IntelliJ Platform product information. | + +## Notebook Helpers +{id="notebook-helpers"} + +| Function | Description | +|-----------------------------------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| `error(message: String)` | Throws an exception with the specified message, which will be printed as the cell's output. | +| `loadPlugins(vararg pluginIds: String)` | Loads plugins installed in the current IDE into the script context based on their plugin IDs. This method also supports optionally loading plugin classes and class loaders. | +| `runInEdt(block: () -> Unit)` | Runs the given block in the [Event Dispatch Thread (EDT)](threading_model.md). If an exception is thrown, it is displayed in the cell's output. | + +## IntelliJ Platform Helpers +{id="intellij-platform-helpers"} + +| Function | Description | +|-----------------------------------------------------------------------------|---------------------------------------------------------------------------------------------------------------------------------------------------------------| +| `currentProject()` | Returns the current open [`Project`](%gh-ic%/platform/core-api/src/com/intellij/openapi/project/Project.java) instance. | +| `currentEditor()` | Returns the current [`FileEditor`](%gh-ic%/platform/editor-ui-api/src/com/intellij/openapi/fileEditor/FileEditor.java) instance or null if no editor is open. | +| `registerExtension(extensionPointName: ExtensionPointName, instance: T)` | Registers an extension programmatically for the given extension point. | +| `registerExtension(extensionPointName: String, instance: T)` | Registers an extension programmatically for the given extension point. | + +## Examples {id="examples"} + +> See [Kotlin Notebook IntelliJ Platform](https://github.com/Kotlin/kotlin-notebook-intellij-platform/tree/master/examples) project repository for more examples. +> +{style="note"} + +### Accessing IDE Information + +```kotlin +println("IDE: ${productInfo.name}") +println("Version: ${productInfo.version}") +println("Build: ${productInfo.buildNumber}") +``` + +### Loading and Using Plugins + +```kotlin +loadPlugins("com.intellij.gradle") +``` + +```kotlin +import com.intellij.gradle.toolingExtension.util.GradleVersionUtil + +GradleVersionUtil.isCurrentGradleAtLeast("8.13.0") +``` + +### Registering Extension + +```kotlin +import com.intellij.codeInsight.editorActions.CopyPastePreProcessor +import com.intellij.openapi.editor.Editor +import com.intellij.openapi.editor.RawText +import com.intellij.openapi.project.Project +import com.intellij.psi.PsiFile + +class MyCopyPastePreProcessor : CopyPastePreProcessor { + override fun preprocessOnCopy( + file: PsiFile?, + startOffsets: IntArray?, + endOffsets: IntArray?, + text: String?, + ) = null + + override fun preprocessOnPaste( + project: Project?, + file: PsiFile?, + editor: Editor?, + text: String?, + rawText: RawText?, + ) = "Hello, World!" +} + +registerExtension(CopyPastePreProcessor.EP_NAME, MyCopyPastePreProcessor()) +``` + +### Rendering Kotlin UI DSL Components + +```kotlin +import com.intellij.ui.dsl.builder.panel +import java.awt.Dimension + +panel { + row { + checkBox("Check me!") + .comment("A comment for this checkbox") + } +}.apply { + size = Dimension(500, 200) +} +``` + +### Rendering Dialog + +```kotlin +import com.intellij.openapi.ui.Messages + +runInEdt { + Messages.showMessageDialog( + null, + "This is a modal dialog message", + "Dialog Title", + Messages.getInformationIcon() + ) +} +``` + +### Creating Disposable Tool Window + +```kotlin +import com.intellij.icons.AllIcons +import com.intellij.openapi.application.runInEdt +import com.intellij.openapi.util.Disposer +import com.intellij.openapi.wm.ToolWindowManager + +val project = currentProject() +val toolWindowManager = ToolWindowManager.getInstance(project) + +runInEdt { + val toolWindow = toolWindowManager.getToolWindow("My Tool Window") + ?: toolWindowManager.registerToolWindow("My Tool Window") { + icon = AllIcons.General.Error + } + + Disposer.register(notebookDisposable) { + toolWindow.remove() + } +} +``` diff --git a/topics/basics/architectural_overview/documents.md b/topics/basics/architectural_overview/documents.md index 4333744ebc9..a39fb167b9a 100644 --- a/topics/basics/architectural_overview/documents.md +++ b/topics/basics/architectural_overview/documents.md @@ -11,11 +11,11 @@ The IntelliJ Platform handles encoding and line break conversions when loading a ## How do I get a `Document`? -| Context | API | -|----------------------------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| -| [Action](action_system.md) | [`AnActionEvent.getData(CommonDataKeys.EDITOR).getDocument()`](%gh-ic%/platform/editor-ui-api/src/com/intellij/openapi/actionSystem/AnActionEvent.java) | -| [PSI File](psi_files.md) | [`PsiDocumentManager.getDocument()`/`getCachedDocument()`](%gh-ic%/platform/core-api/src/com/intellij/psi/PsiDocumentManager.java) | -| [Virtual File](virtual_file.md) |

    [`FileDocumentManager.getDocument()`](%gh-ic%/platform/core-api/src/com/intellij/openapi/fileEditor/FileDocumentManager.java) (forces the document content to be loaded from a disk if it wasn't loaded previously)

    [`FileDocumentManager.getCachedDocument()`](%gh-ic%/platform/core-api/src/com/intellij/openapi/fileEditor/FileDocumentManager.java) (use if only open or possibly modified documents are relevant)

    | +| Context | API | +|---------------------------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| [Action](action_system.md) | [`AnActionEvent.getData(CommonDataKeys.EDITOR).getDocument()`](%gh-ic%/platform/editor-ui-api/src/com/intellij/openapi/actionSystem/AnActionEvent.java) | +| [PSI File](psi_files.md) | [`PsiDocumentManager.getDocument()`/`getCachedDocument()`](%gh-ic%/platform/core-api/src/com/intellij/psi/PsiDocumentManager.java) | +| [Virtual File](virtual_file.md) |

    [`FileDocumentManager.getDocument()`](%gh-ic%/platform/core-api/src/com/intellij/openapi/fileEditor/FileDocumentManager.java) (forces the document content to be loaded from a disk if it wasn't loaded previously)

    [`FileDocumentManager.getCachedDocument()`](%gh-ic%/platform/core-api/src/com/intellij/openapi/fileEditor/FileDocumentManager.java) (use if only open or possibly modified documents are relevant)

    | ## What can I do with a `Document`? @@ -38,18 +38,18 @@ Thus, an unmodified `Document` instance can be garbage-collected if no one refer ## How do I create a `Document`? For creating a new file on disk, please do not create a `Document` but a PSI file and get its `Document` (see [](psi_files.md#how-do-i-create-a-psi-file)). -To create a `Document` instance that isn't bound to anything, use [`EditorFactory.createDocument()`](%gh-ic%/platform/editor-ui-api/src/com/intellij/openapi/editor/EditorFactory.java). +To create a `Document` instance not bound to anything, use [`EditorFactory.createDocument()`](%gh-ic%/platform/editor-ui-api/src/com/intellij/openapi/editor/EditorFactory.java). ## How do I get notified when documents change? * `Document.addDocumentListener()` allows receiving notifications about changes in a particular `Document` instance. * `EditorFactory.getEventMulticaster().addDocumentListener()` allows receiving notifications about changes in all open documents. -* Register [`FileDocumentManagerListener`](%gh-ic%/platform/platform-api/src/com/intellij/openapi/fileEditor/FileDocumentManagerListener.java) [listener](plugin_listeners.md) or subscribe to `AppTopics.FILE_DOCUMENT_SYNC` on any level bus to receive notifications when a `Document` is saved or reloaded from disk. +* Register a [`FileDocumentManagerListener`](%gh-ic%/platform/core-api/src/com/intellij/openapi/fileEditor/FileDocumentManagerListener.java) [listener](plugin_listeners.md) or subscribe to `AppTopics.FILE_DOCUMENT_SYNC` on any level bus to receive notifications when a `Document` is saved or reloaded from disk. ## What are the rules of working with documents? -The general read/write action rules are in effect (see [](threading_model.md)). -Besides, any operations which modify the contents of the document must be wrapped in a command ([`CommandProcessor.executeCommand()`](%gh-ic%/platform/core-api/src/com/intellij/openapi/command/CommandProcessor.java)). +The general [read/write action rules](threading_model.md#read-write-lock) are in effect. +Besides, any operations that modify the contents of the document must be wrapped in a command ([`CommandProcessor.executeCommand()`](%gh-ic%/platform/core-api/src/com/intellij/openapi/command/CommandProcessor.java)). `executeCommand()` calls can be nested, and the outermost `executeCommand()` call is added to the undo stack. If multiple documents are modified within a command, undoing this command will, by default, show a confirmation dialog to the user. diff --git a/topics/basics/architectural_overview/element_patterns.md b/topics/basics/architectural_overview/element_patterns.md index 506a4897855..e938c4ddfe4 100644 --- a/topics/basics/architectural_overview/element_patterns.md +++ b/topics/basics/architectural_overview/element_patterns.md @@ -49,7 +49,7 @@ XmlAttributeValuePattern attributeValueInFxml = ``` As shown in the code above, element patterns can be stacked and combined to create more complex conditions. -[`JsonCompletionContributor`](%gh-ic%/json/src/com/intellij/json/codeinsight/JsonCompletionContributor.java) contains another example with more requirements on the PSI element. +[`JsonCompletionContributor`](%gh-ic%/json/backend/src/com/intellij/json/codeinsight/JsonCompletionContributor.java) contains another example with more requirements on the PSI element. ```java PsiElementPattern.Capture AFTER_COMMA_OR_BRACKET_IN_ARRAY = diff --git a/topics/basics/architectural_overview/modifying_psi.md b/topics/basics/architectural_overview/modifying_psi.md index 47526d87667..7b05e6dc877 100644 --- a/topics/basics/architectural_overview/modifying_psi.md +++ b/topics/basics/architectural_overview/modifying_psi.md @@ -1,13 +1,13 @@ - + # Modifying the PSI Creating, deleting, and modifying PSI elements. The PSI is a read/write representation of the source code as a tree of elements corresponding to a source file's structure. -You can modify the PSI by *adding*, *replacing*, and *deleting* PSI elements. +The PSI can be modified by *adding*, *replacing*, and *deleting* PSI elements. -To perform these operations, you use methods such as `PsiElement.add()`, `PsiElement.delete()`, and `PsiElement.replace()`, as well as other methods defined in the [`PsiElement`](%gh-ic%/platform/core-api/src/com/intellij/psi/PsiElement.java) interface that let you process multiple elements in a single operation, or to specify the exact location in the tree where an element needs to be added. +To perform these operations, use methods such as `PsiElement.add()`, `PsiElement.delete()`, `PsiElement.replace()`, and similar methods allowing to process multiple elements in a single operation, or to specify the exact location in the tree where an element needs to be added. Like document operations, PSI modifications need to be wrapped in a write action and in command (and can only be performed in the event dispatch thread). See [the Documents article](documents.md#what-are-the-rules-of-working-with-documents) for more information on commands and write actions. @@ -15,17 +15,19 @@ See [the Documents article](documents.md#what-are-the-rules-of-working-with-docu ## Creating the New PSI The PSI elements to add to the tree or replace existing PSI elements are usually *created from text*. -In the most general case, you use the `createFileFromText()` method of [`PsiFileFactory`](%gh-ic%/platform/core-api/src/com/intellij/psi/PsiFileFactory.java) to create a new file that contains the code construct which you need to add to the tree or to use as a replacement for an existing element, traverse the resulting tree to locate the specific part that you need, and then pass that element to `add()` or `replace()`. -See also [](psi_files.md#how-do-i-create-a-psi-file). +In most cases, the flow is: + +1. Use [`PsiFileFactory.createFileFromText()`](%gh-ic%/platform/core-api/src/com/intellij/psi/PsiFileFactory.java) to create a new file that contains the code construct that needs to be added to the tree or used as a replacement for an existing element. See also [](psi_files.md#how-do-i-create-a-psi-file). +2. Traverse the resulting tree to locate the required element and then pass it to `add()` or `replace()`. + +Most languages provide factory methods to create specific code constructs more easily, for example: -Most languages provide factory methods that let you create specific code constructs more easily. -Examples: * [`PsiJavaParserFacade`](%gh-ic%/java/java-psi-api/src/com/intellij/psi/PsiJavaParserFacade.java) class contains methods such as `createMethodFromText()`, which creates a Java method from the given text * [`SimpleElementFactory.createProperty()`](%gh-sdk-samples-master%/simple_language_plugin/src/main/java/org/intellij/sdk/language/psi/SimpleElementFactory.java) creating a Simple language property -When you're implementing refactorings, [intentions](code_intentions.md), or inspection [quickfixes](code_inspections_and_intentions.md) that work with existing code, the text that you pass to the various `createFromText()` methods will combine hard-coded fragments and fragments of code taken from the existing file. -For small code fragments (individual identifiers), you can simply append the text from the existing code to the text of the code fragment you are building. -In that case, you need to make sure that the resulting text is syntactically correct. +When implementing refactorings, [intentions](code_intentions.md), or inspection [quickfixes](code_inspections_and_intentions.md) that work with existing code, the text passed to the various `createFromText()` methods will combine hard-coded fragments and fragments of code taken from the existing file. +For small code fragments (individual identifiers), append the text from the existing code to the text of the code fragment being built. +In that case, make sure that the resulting text is syntactically correct. Otherwise, the `createFromText()` method will throw an exception. For larger code fragments, it's best to perform the modification in several steps: @@ -45,25 +47,27 @@ As an example of this approach, see the quickfix in the `ComparingStringReferenc ## Maintaining Tree Structure Consistency -The PSI modification methods do not restrict you in the way you can build the resulting tree structure. -For example, when working with a Java class, you can add a `for` statement as a direct child of a `PsiMethod` element, even though the Java parser will never produce such a structure (the `for` statement will always be a child of the `PsiCodeBlock`) representing the method body. +The PSI modification methods do not restrict the way of building the resulting tree structure. + +For example, when working with a Java class, it is possible to add a `for` statement as a direct child of a `PsiMethod` element, even though the Java parser will never produce such a structure (the `for` statement will always be a child of the `PsiCodeBlock`) representing the method body. + Modifications that produce incorrect tree structures may appear to work, but they will lead to problems and exceptions later. -Therefore, you always need to ensure that the structure you built with PSI modification operations is the same as what the parser would produce when parsing the code that you've created. +Therefore, always ensure that the structure built with PSI modification operations is the same as what the parser would produce when parsing the created code. -To make sure you're not introducing inconsistencies, you can call `PsiTestUtil.checkFileStructure()` in the tests for your action that modifies the PSI. -This method ensures that the structure you've built is the same as what the parser produces. +To make sure inconsistencies are not introduced, use `PsiTestUtil.checkFileStructure()` in the tests for actions modifying the PSI. +This method ensures that the built structure is the same as what the parser produces. ## Whitespaces and Imports -When working with PSI modification functions, you should never create individual whitespace nodes (spaces or line breaks) from the text. +When working with PSI modification functions, do not create individual whitespace nodes (spaces or line breaks) from text. Instead, all whitespace modifications are performed by the formatter, which follows the code style settings selected by the user. -Formatting is automatically performed at the end of every command, and if you need, you can also perform it manually using the `reformat(PsiElement)` method in the [`CodeStyleManager`](%gh-ic%/platform/core-api/src/com/intellij/psi/codeStyle/CodeStyleManager.java) class. +Formatting is automatically performed at the end of every command and can be also performed manually with [`CodeStyleManager.reformat(PsiElement)`](%gh-ic%/platform/core-api/src/com/intellij/psi/codeStyle/CodeStyleManager.java) if needed. -Also, when working with Java code (or with code in other languages with a similar import mechanism such as Groovy or Python), you should never create imports manually. -Instead, you should insert fully-qualified names into the code you're generating, and then call the `shortenClassReferences()` method in the [`JavaCodeStyleManager`](%gh-ic%/java/java-psi-api/src/com/intellij/psi/codeStyle/JavaCodeStyleManager.java) (or the equivalent API for the language you're working with). +Also, when working with Java code (or with code in other languages with a similar import mechanism such as Groovy or Python), do not create imports manually. +Instead, use fully qualified names in generated code and then call [`JavaCodeStyleManager.shortenClassReferences()`](%gh-ic%/java/java-psi-api/src/com/intellij/psi/codeStyle/JavaCodeStyleManager.java) (or the equivalent API for the code language). This ensures that the imports are created according to the user's code style settings and inserted into the file's correct place. ## Combining PSI and Document Modifications -In some cases, you need to perform a PSI modification and then to perform an operation on the document you've just modified through the PSI (for example, start a [live template](live_templates.md)). -To complete the PSI-based post-processing (such as formatting) and commit the changes to the document, call `doPostponedOperationsAndUnblockDocument()` on [`PsiDocumentManager`](%gh-ic%/platform/core-api/src/com/intellij/psi/PsiDocumentManager.java) instance. +In some cases, after modifying a PSI, it is required to perform an operation on the modified document (for example, start a [live template](live_templates.md)). +To complete the PSI-based post-processing (such as formatting) and commit the changes to the document, call [`PsiDocumentManager.doPostponedOperationsAndUnblockDocument()`](%gh-ic%/platform/core-api/src/com/intellij/psi/PsiDocumentManager.java). diff --git a/topics/basics/architectural_overview/psi_elements.md b/topics/basics/architectural_overview/psi_elements.md index f30ac3ff9f4..fc68a6feecb 100644 --- a/topics/basics/architectural_overview/psi_elements.md +++ b/topics/basics/architectural_overview/psi_elements.md @@ -13,7 +13,7 @@ For example, you can use PSI elements to perform code analysis, such as [code in The [`PsiElement`](%gh-ic%/platform/core-api/src/com/intellij/psi/PsiElement.java) class is the common base class for PSI elements. -> PSI classes for specific languages usually start with a language prefix, for example, [`JsonArray`](%gh-ic%/json/split/gen/com/intellij/json/psi/JsonArray.java). +> PSI classes for specific languages usually start with a language prefix, for example, [`JsonArray`](%gh-ic%/json/gen/com/intellij/json/psi/JsonArray.java). > > The Java PSI API, developed many years ago when there was no plan to support other languages, uses the `Psi` prefix, for example, [`PsiIdentifier`](%gh-ic%/java/java-psi-api/src/com/intellij/psi/PsiIdentifier.java) or [`PsiElementFactory`](%gh-ic%/java/java-psi-api/src/com/intellij/psi/PsiElementFactory.java). > Don't confuse Java with the core PSI API. diff --git a/topics/basics/architectural_overview/psi_performance.md b/topics/basics/architectural_overview/psi_performance.md index f3aa30ebac7..1161c0ff5d4 100644 --- a/topics/basics/architectural_overview/psi_performance.md +++ b/topics/basics/architectural_overview/psi_performance.md @@ -1,4 +1,4 @@ - + # PSI Performance @@ -8,9 +8,63 @@ See also [](threading_model.md#avoiding-ui-freezes) and [](indexing_and_psi_stub > [IDE Perf](https://plugins.jetbrains.com/plugin/15104-ide-perf) plugin provides on-the-fly performance diagnostic tools, including a dedicated view for [`CachedValue`](#cache-results-of-heavy-computations) metrics. +## Overview + +PSI has a lot of time-space compromises. +There are tons of PSI elements in IDE memory, so the IntelliJ Platform and language plugins strive to keep them as compact as possible, storing very little data inside. +As a result, many things are recomputed on every call of getter methods on `PsiElement` and its subclasses. +They are not stored inside the fields of `PsiElement`s. + +For example, consider the following Java expression: + +```java +String.format("Hello, %s!", name); +``` + +This is its (simplified) PSI: + +``` +PsiMethodCallExpression:String.format("Hello, %s!", name) + PsiReferenceExpression:String.format + PsiExpressionList + PsiJavaToken:LPARENTH + PsiLiteralExpression:"Hello, %s!" + PsiJavaToken:COMMA + PsiReferenceExpression:name + PsiJavaToken:RPARENTH +``` + +Assume that plugin code receives `PsiMethodCallExpression call` and needs to get the first and last expression passed as arguments to this method call. +This can be done with `methodCall.getArgumentList().getExpressions()`, which does the following: +1. `getArgumentList()` traverses the linked list of children, looking for an element of a proper type (in this case – `PsiExpressionList`) +2. `getExpressions()` traverses the children to find all the expressions (elements of `PsiExpression`), then allocates an array of the target size, and then traverses the children again to fill in this array. + +These `get*()` methods are not simple getters that return a readily available value – keep this in mind when working with PSI. + +As a rule, avoid calling the same method twice, one after another. +Instead, it's better to store the result in a local variable. + +Find the first and last expression argument passed to a method call could be implemented as follows: + + + +```java +PsiExpression first = call.getArgumentList().getExpressions()[0]; +int lastIndex = call.getArgumentList().getExpressionCount() - 1; +PsiExpression last = call.getArgumentList().getExpressions()[lastIndex]; +``` + +```java +PsiExpression[] expressions = call.getArgumentList().getExpressions(); +PsiExpression first = expressions[0]; +PsiExpression last = expressions[expressions.length - 1]; +``` + + + ## Avoid Expensive Methods of `PsiElement` -Avoid `PsiElement`'s methods which are expensive with deep trees. +Avoid `PsiElement`'s methods, which are expensive with deep trees. `getText()` traverses the whole tree under the given element and concatenates strings, consider using `textMatches()` instead. @@ -19,13 +73,13 @@ If you only need PSI element length, use `getTextLength()`. `getContainingFile()` and `getProject()` often can be computed once per task and then stored in fields or passed via parameters. -Additionally, methods such as `getText()`, `getNode()`, or `getTextRange()`, need the AST, obtaining which can be quite an expensive operation, see next section. +Additionally, methods such as `getText()`, `getNode()`, or `getTextRange()` require the AST, and accessing it can be an expensive operation, as explained in the next section. ## Avoid Using Many PSI Trees/Documents Avoid loading too many parsed trees or documents into memory at the same time. Ideally, only AST nodes from files open in the editor should be present in the memory. -Everything else, even if it's needed for resolve/highlighting purposes, can be accessed via PSI interfaces, but its implementations should [use stubs](stub_indexes.md) underneath, which are less CPU- and memory-expensive. +Everything else, even if it's necessary for resolve/highlighting purposes, can be accessed via PSI interfaces, but its implementations should [use stubs](stub_indexes.md) underneath, which are less CPU- and memory-expensive. If stubs don't suit your case well (e.g., the information you need is large and/or very rarely needed, or you're developing a plugin for a language whose PSI you don't control), you can create a [custom index or gist](indexing_and_psi_stubs.md). @@ -40,17 +94,17 @@ If you still need documents, then at least ensure you load them one by one and d Method calls such as `PsiElement.getReference()` (and `getReferences()`), `PsiReference.resolve()` (and `multiResolve()` and other equivalents) or computation of expression types, type inference results, control flow graphs, etc. can be expensive. To avoid paying this cost several times, the result of such computation can be cached and reused. -Usually, [`CachedValue`](%gh-ic%/platform/core-api/src/com/intellij/psi/util/CachedValue.java) created with [`CachedValueManager`](%gh-ic%/platform/core-api/src/com/intellij/psi/util/CachedValuesManager.java) works well for this purpose. +Usually, [`CachedValue`](%gh-ic%/platform/core-api/src/com/intellij/psi/util/CachedValue.java) created with [`CachedValuesManager`](%gh-ic%/platform/core-api/src/com/intellij/psi/util/CachedValuesManager.java) works well for this purpose. If the information you cache depends only on a subtree of the current PSI element (and nothing else: no resolve results or other files), you can cache it in a field in your `PsiElement` implementation and drop the cache in an override of `ASTDelegatePsiElement.subtreeChanged()`. -### Using `ProjectRootManager` as Dependency +### Using `ProjectRootManager` as a Dependency {id="projectRootManagerDependency"} The platform no longer increments root changes modification tracker on finish of [dumb mode](indexing_and_psi_stubs.md#dumb-mode). -If cached values use [`ProjectRootManager`](%gh-ic%/platform/projectModel-api/src/com/intellij/openapi/roots/ProjectRootManager.java) as dependency +If cached values use [`ProjectRootManager`](%gh-ic%/platform/projectModel-api/src/com/intellij/openapi/roots/ProjectRootManager.java) as a dependency (without [`PsiModificationTracker`](%gh-ic%/platform/core-api/src/com/intellij/psi/util/PsiModificationTracker.java)) and at the same time depend on [indexes](indexing_and_psi_stubs.md), a dependency on [`DumbService`](%gh-ic%/platform/core-api/src/com/intellij/openapi/project/DumbService.kt) must be added. diff --git a/topics/basics/architectural_overview/psi_references.md b/topics/basics/architectural_overview/psi_references.md index 6bd5294196a..92a5d9718c4 100644 --- a/topics/basics/architectural_overview/psi_references.md +++ b/topics/basics/architectural_overview/psi_references.md @@ -93,7 +93,7 @@ Resolving a reference means going from usage to the corresponding declaration. To perform the navigation in the opposite direction - from a declaration to its usages - perform a _references search_. To perform a search using [`ReferencesSearch`](%gh-ic%/platform/indexing-api/src/com/intellij/psi/search/searches/ReferencesSearch.java), specify the element to search for, and optionally other parameters such as the scope in which the reference needs to be searched. -The created [`Query`](%gh-ic%/platform/core-api/src/com/intellij/util/Query.java) allows obtaining all results at once or iterating over the results one by one. +The created [`Query`](%gh-ic%/platform/core-api/src/com/intellij/util/Query.kt) allows obtaining all results at once or iterating over the results one by one. The latter allows stopping processing as soon as the first (matching) result has been found. ## Implementing References diff --git a/topics/basics/architectural_overview/threading/background_processes.md b/topics/basics/architectural_overview/threading/background_processes.md index 7affa74f581..c68c88fa4ad 100644 --- a/topics/basics/architectural_overview/threading/background_processes.md +++ b/topics/basics/architectural_overview/threading/background_processes.md @@ -140,7 +140,7 @@ See the section below for handling cancellation. The cancellation is handled in the running process code by calling `ProgressIndicator.checkCanceled()`, or `ProgressManager.checkCanceled()`, if no indicator instance is available in the current context. -If the process was [marked as canceled](#requesting-cancellation), then the call to `checkCanceled()` throws an instance of a special unchecked [`ProcessCanceledException`](%gh-ic%/platform/util/base/src/com/intellij/openapi/progress/ProcessCanceledException.java) (PCE) and the actual cancellation happens. +If the process was [marked as canceled](#requesting-cancellation), then the call to `checkCanceled()` throws an instance of a special unchecked [`ProcessCanceledException`](%gh-ic%/platform/util/base/multiplatform/src/com/intellij/openapi/progress/ProcessCanceledException.kt) (PCE) and the actual cancellation happens. This exception doesn't represent any error and is only used to handle cancellation for convenience. It allows canceling processes deeply in the call stack, without the need to handle cancellation on each level. diff --git a/topics/basics/architectural_overview/threading/coroutines/coroutine_read_actions.topic b/topics/basics/architectural_overview/threading/coroutines/coroutine_read_actions.topic index 74ea8753160..0ab59a12ba4 100644 --- a/topics/basics/architectural_overview/threading/coroutines/coroutine_read_actions.topic +++ b/topics/basics/architectural_overview/threading/coroutines/coroutine_read_actions.topic @@ -1,6 +1,6 @@ - + @@ -12,12 +12,12 @@

    - The concept of read/write locks and running blocking and cancellable read actions is explained in + The concept of read/write locks and running blocking and non-blocking read actions is explained in the Threading section:

    -
  • Read-Write Lock
  • -
  • Read Action Cancellability
  • +
  • +
  • This section explains running read actions (RA) in coroutines specifically.

    @@ -69,7 +69,7 @@ Application.runReadAction
    and similar methods (without any prefix/suffix) perform RA blocking WA, whereas RA allowing WA are invoked via - the NonBlockingReadAction API. + the NonBlockingReadAction API.

    Be careful when migrating the code running read actions to coroutines.

    @@ -171,7 +171,7 @@

    To check whether the current action was canceled, clients must call ProgressManager.checkCanceled(), which was adjusted to work in coroutines. - Clients mustn't throw ProcessCanceledException manually. + Clients mustn't throw ProcessCanceledException manually.

    diff --git a/topics/basics/architectural_overview/threading/coroutines/coroutine_scopes.md b/topics/basics/architectural_overview/threading/coroutines/coroutine_scopes.md index da10f3db88e..a19c501b0ce 100644 --- a/topics/basics/architectural_overview/threading/coroutines/coroutine_scopes.md +++ b/topics/basics/architectural_overview/threading/coroutines/coroutine_scopes.md @@ -86,9 +86,13 @@ See [](launching_coroutines.md#launching-coroutine-from-service-scope) for full ### Use Service Scopes -If a plugin requires running some code in a coroutine, the recommended approach is to create a separate [service](plugin_services.md) that will receive its [own scope](#service-scopes) via constructor and launch the coroutine in this scope. +If a plugin requires running some code in a coroutine, the approach recommended in most cases is to create a separate [service](plugin_services.md) that will receive its [own scope](#service-scopes) via constructor and launch the coroutine in this scope. This approach guarantees the usage of the correct scope, preventing leaks and canceling wrong scopes and killing all their (e.g., application's or project's) coroutines accidentally. +> Note that since 2024.2, `AnAction.actionPerformed()` logic can be executed in the [current thread coroutine scope](launching_coroutines.md#using-currentthreadcoroutinescope). +> +{style="note"} + See the [](launching_coroutines.md) section for details. > The following sections describe the potential problems that would occur if the wrong coroutine scopes were used. diff --git a/topics/basics/architectural_overview/threading/coroutines/launching_coroutines.md b/topics/basics/architectural_overview/threading/coroutines/launching_coroutines.md index 73ff27bfcd4..30e0fa7114a 100644 --- a/topics/basics/architectural_overview/threading/coroutines/launching_coroutines.md +++ b/topics/basics/architectural_overview/threading/coroutines/launching_coroutines.md @@ -1,4 +1,4 @@ - + # Launching Coroutines @@ -7,14 +7,15 @@ -There are two approaches to launching coroutines in the IntelliJ Platform: -1. [Service with its own scope](#launching-coroutine-from-service-scope). (recommended) -2. [The `runBlockingCancellable` function](#using-runblockingcancellable). +In the IntelliJ Platform, coroutines can be launched with one of the following approaches: +1. [Service with its own scope](#launching-coroutine-from-service-scope). +2. The [`currentThreadCoroutineScope`](#using-currentthreadcoroutinescope) function for [executing actions](action_system.md#overriding-the-anactionactionperformed-method). +3. The [`runBlockingCancellable`](#using-runblockingcancellable) function. (not recommended) ## Launching Coroutine From Service Scope The recommended approach is creating a [service](plugin_services.md) that receives [its scope](coroutine_scopes.md#service-scopes) via the constructor injection and launching a coroutine from the service methods. -Please note that while creating a service instance does allocate additional resources, using a dedicated service and scope remains a lightweight and, most importantly, safe solution for launching coroutines. +Note that while creating a service instance does allocate additional resources, using a dedicated service and scope remains a lightweight and fundamentally safe solution for launching coroutines. It should be used whenever possible. The pattern is as follows: @@ -58,6 +59,31 @@ class MyProjectService( The injected scope is created per service, so each instance has its own isolated scope with a common parent, which is an [intersection scope](coroutine_scopes.md#intersection-scopes). The injected scope is canceled when the container (application/project) is shut down or when the plugin is unloaded. +## Using `currentThreadCoroutineScope` + +Action behavior performed in [`AnAction.actionPerformed()`](action_system.md#overriding-the-anactionactionperformed-method) can be executed in a coroutine via [`currentThreadCoroutineScope`](%gh-ic%/platform/core-api/src/com/intellij/openapi/progress/coroutines.kt): + +```kotlin +internal class MyAction : AnAction() { + override fun actionPerformed(e: AnActionEvent) { + val file = e.getData(LangDataKeys.PSI_FILE) ?: return + currentThreadCoroutineScope().launch { + // use suspending APIs: + val targets = readAction { + // do something in read + } + withContext(Dispatchers.EDT) { + // show some UI + } + } + } + // ... +} +``` + +Compared to the [service scope](#launching-coroutine-from-service-scope) approach, using `currentThreadCoroutineScope()` enables Action System infrastructure to control the launched coroutine and cancel it if needed. +In the case of service scopes, the infrastructure code can't control a coroutine launched from an action, as service scopes are "more global" and live longer than the action trigger. + ## Using `runBlockingCancellable` > Using `runBlockingCancellable` is not recommended. diff --git a/topics/basics/architectural_overview/threading/threading_model.md b/topics/basics/architectural_overview/threading/threading_model.md index e955eb3d6b5..96da25cd06e 100644 --- a/topics/basics/architectural_overview/threading/threading_model.md +++ b/topics/basics/architectural_overview/threading/threading_model.md @@ -181,7 +181,7 @@ The IntelliJ Platform provides a simple API for accessing data under read or wri Read and write actions allow executing a piece of code under a lock, automatically acquiring it before an action starts, and releasing it after the action is finished. > Always try to wrap only the required operations into read/write actions, minimizing the time of holding locks. -> If the read operation itself is long, consider using one of the [read action cancellability techniques](#read-action-cancellability) to avoid blocking the write lock and EDT. +> If the read operation itself is long, consider using [non-blocking read actions](#non-blocking-read-actions) to avoid blocking the write lock and EDT. > {style="warning" title="Minimize Locking Scopes"} @@ -516,9 +516,9 @@ The following table presents methods providing useful modality states to be pass > {style="note"} -## Read Action Cancellability +## Non-Blocking Read Actions -BGT shouldn't hold read locks for a long time. +BGT shouldn't hold [read locks](#read-actions) for a long time. The reason is that if EDT needs a write action (for example, the user types something in the editor), it must be acquired as soon as possible. Otherwise, the UI will freeze until all BGTs have released their read actions. The following diagram presents this problem: @@ -573,13 +573,17 @@ The total execution time of the read action will be longer due to multiple attem The canceling approach is widely used in various areas of the IntelliJ Platform: editor highlighting, code completion, "go to class/file/…" actions all work like this. Read the [](background_processes.md) section for more details. -### Cancellable Read Actions API +> Note that APIs mentioned in [Read Actions API](#read-actions-api) (except suspending `readAction()`) are blocking. +> +{style="warning"} + +### Non-Blocking Read Actions API > Plugins targeting versions 2024.1+ should use Write Allowing Read Actions available in the [Kotlin Coroutines Read Actions API](coroutine_read_actions.topic#coroutine-read-actions-api). > {style="warning"} -To run a cancellable read action, use one of the available APIs: +To run a non-blocking read action, use one of the available APIs: - [`ReadAction.nonBlocking()`](%gh-ic%/platform/core-api/src/com/intellij/openapi/application/ReadAction.java) which returns [`NonBlockingReadAction`](%gh-ic%/platform/core-api/src/com/intellij/openapi/application/NonBlockingReadAction.java) (NBRA). NBRA handles restarting the action out-of-the-box. - [`ReadAction.computeCancellable()`](%gh-ic%/platform/core-api/src/com/intellij/openapi/application/ReadAction.java) which computes the result immediately in the current thread or throws an exception if there is a running or requested write action. @@ -612,7 +616,7 @@ review the documentation of `AnAction.getActionUpdateThread()` in the [](action_ #### Minimize Write Actions Scope Write actions currently [have to happen on EDT](#locks-and-edt). -To speed them up, as much as possible should be moved out of the write action into a preparation step which can be then invoked in the [background](background_processes.md) or inside an [NBRA](#cancellable-read-actions-api). +To speed them up, as much as possible should be moved out of the write action into a preparation step which can be then invoked in the [background](background_processes.md) or inside an [NBRA](#non-blocking-read-actions-api). #### Slow Operations on EDT Assertion @@ -629,12 +633,28 @@ Ideally, they should only clear some caches. It is also possible to schedule background processing of events. In such cases, be prepared that some new events might be delivered before the background processing starts – and thus the world might have changed by that moment or even in the middle of background processing. -Consider using [`MergingUpdateQueue`](%gh-ic%/platform/ide-core/src/com/intellij/util/ui/update/MergingUpdateQueue.kt) and [NBRA](#cancellable-read-actions-api) to mitigate these issues. +Consider using [`MergingUpdateQueue`](%gh-ic%/platform/ide-core/src/com/intellij/util/ui/update/MergingUpdateQueue.kt) and [NBRA](#non-blocking-read-actions-api) to mitigate these issues. ### VFS Events Massive batches of VFS events can be pre-processed in the background with [`AsyncFileListener`](%gh-ic%/platform/core-api/src/com/intellij/openapi/vfs/AsyncFileListener.java). +### Investigating UI Freezes + +See the [Investigating IntelliJ Platform UI Freezes](https://blog.jetbrains.com/platform/2025/09/investigating-intellij-platform-ui-freezes/) blog post for techniques to investigate UI freezes. + +## Kotlin Notebooks + +IntelliJ Platform sources include Kotlin Notebooks helping to understand the core concepts of the threading model: +1. [Context Propagation](%gh-ic-master%/docs/notebooks/1-ContextPropagation.ipynb) +2. [Cancellation Model](%gh-ic-master%/docs/notebooks/2-CancellationModel.ipynb) +3. [Read-Write Lock](%gh-ic-master%/docs/notebooks/3-ReadWriteLock.ipynb) + +The notebooks contain concept explanations accompanied by code that can be run interactively in the IDE. +Code can be changed for experimentation. + +See more information about the integration of [Kotlin Notebooks with the IntelliJ Platform](tools_kotlin_notebook.md). + ## FAQ ### How to check whether the current thread is the EDT/UI thread? diff --git a/topics/basics/architectural_overview/virtual_file_system.md b/topics/basics/architectural_overview/virtual_file_system.md index ddd0cc6e236..eda8404964b 100644 --- a/topics/basics/architectural_overview/virtual_file_system.md +++ b/topics/basics/architectural_overview/virtual_file_system.md @@ -13,23 +13,23 @@ It serves the following main purposes: * Providing a possibility to [associate additional persistent data](virtual_file.md#how-can-i-store-additional-metadata-in-files) with a file in the VFS. To provide the last two features, the VFS manages a _persistent snapshot_ of some of the user's hard disk contents. -The snapshot stores only those files which have been requested at least once through the VFS API, and is asynchronously updated to match the changes happening on the disk. +The snapshot stores only those files which have been requested at least once through the VFS API and is asynchronously updated to match the changes happening on the disk. The snapshot is application level, not project level - so, if some file (for example, a class in the JDK) is referenced by multiple projects, only one copy of its contents will be stored in the VFS. All VFS access operations go through the snapshot. -If some information is requested through the VFS APIs and is not available in the snapshot, it is loaded from disk and stored into the snapshot. +If some information is requested through the VFS APIs and is not available in the snapshot, it is loaded from the disk and stored into the snapshot. If the information is available in the snapshot, the snapshot data is returned. The contents of files and the lists of files in directories are stored in the snapshot only if that specific information was accessed. Otherwise, only file metadata like name, length, timestamp, attributes are stored. -> This means that the state of the file system and the file contents displayed in the IntelliJ Platform UI comes from the snapshot, which may not always match the disk's actual contents. +> This means that the state of the file system and the file contents displayed in the IntelliJ Platform UI come from the snapshot, which may not always match the disk's actual contents. > For example, in some cases, deleted files can still be visible in the UI for some time before the deletion is picked up by the IntelliJ Platform. > {style="note"} -The snapshot is updated from disk during _refresh operations_, which generally happen asynchronously. +The snapshot is updated from the disk during _refresh operations_, which generally happen asynchronously. All write operations made through the VFS are synchronous - i.e., the contents are saved to disk immediately. A refresh operation synchronizes the state of a part of the VFS with the actual disk contents. @@ -44,7 +44,7 @@ On Windows, Mac, and Linux, a native file watcher process is started that receiv If a file watcher is available, a refresh operation looks only at the files that have been reported as changed by the file watcher. If no file watcher is present, a refresh operation walks through all directories and files in the refresh scope. -> Invoke [internal action](internal_actions_intro.md) Tools | Internal Actions | VFS | Show Watched VFS Roots to see all registered roots for current project. +> Invoke the [internal action](internal_actions_intro.md) Tools | Internal Actions | VFS | Show Watched VFS Roots to see all registered roots for the current project. > Refresh operations are based on file timestamps. @@ -67,7 +67,7 @@ In fact, the refresh operations are executed according to their own threading po The synchronous flag simply means that the calling thread will be blocked until the refresh operation (which will most likely run on a different thread) is completed. Both synchronous and asynchronous refreshes can be initiated from any thread. -If a refresh is initiated from a background thread, the calling thread must not hold a read action, because otherwise, a deadlock would occur. +If a refresh is initiated from a background thread, the calling thread must not hold a read lock, because otherwise, a deadlock would occur. See [IntelliJ Platform Architectural Overview](threading_model.md) for more details on the threading model and read/write actions. The same threading requirements also apply to functions like [`LocalFileSystem.refreshAndFindFileByPath()`](%gh-ic%/platform/analysis-api/src/com/intellij/openapi/vfs/LocalFileSystem.java), which perform a partial refresh if the file with the specified path is not found in the snapshot. @@ -82,12 +82,12 @@ In some cases, synchronous refreshes can cause deadlocks, depending on which [lo ## Virtual File System Events -All changes happening in the virtual file system, either due to refresh operations or caused by user actions, are reported as _virtual file system events_. +All changes happening in the virtual file system (either due to refresh operations or caused by user actions) are reported as _virtual file system events_. VFS events are always fired in the event dispatch thread and in a write action. The most efficient way to listen to VFS events is to implement [`BulkFileListener`](%gh-ic%/platform/core-api/src/com/intellij/openapi/vfs/newvfs/BulkFileListener.java) and to subscribe with it to the [`VirtualFileManager.VFS_CHANGES`](%gh-ic%/platform/core-api/src/com/intellij/openapi/vfs/VirtualFileManager.java) topic. A non-blocking variant [`AsyncFileListener`](%gh-ic%/platform/core-api/src/com/intellij/openapi/vfs/AsyncFileListener.java) is also available. -See [How do I get notified when VFS changes?](virtual_file.md#how-do-i-get-notified-when-vfs-changes) for implementation details. +See [](virtual_file.md#how-do-i-get-notified-when-vfs-changes) for implementation details. > VFS listeners are application level and will receive events for changes happening in *all* the projects opened by the user. > You may need to filter out events that aren't relevant to your task (e.g., via [`ProjectFileIndex.isInContent()`](%gh-ic%/platform/projectModel-api/src/com/intellij/openapi/roots/ProjectFileIndex.java)). @@ -96,10 +96,10 @@ See [How do I get notified when VFS changes?](virtual_file.md#how-do-i-get-notif VFS events are sent both before and after each change, and you can access the old contents of the file in the before event. Note that events caused by a refresh are sent after the changes have already occurred on disk. -So when you process the `beforeFileDeletion` event, for example, the file has already been deleted from disk. +So when you process the `beforeFileDeletion` event, for example, the file has already been deleted from the disk. However, it is still present in the VFS snapshot, and you can access its last contents using the VFS API. Note that a refresh operation fires events only for changes in files that have been loaded in the snapshot. For example, if you accessed a `VirtualFile` for a directory but never loaded its contents using [`VirtualFile.getChildren()`](%gh-ic%/platform/core-api/src/com/intellij/openapi/vfs/VirtualFile.java), you may not get `fileCreated` notifications when files are created in that directory. -If you loaded only a single file in a directory using `VirtualFile.findChild()`, you will get notifications for changes to that file, but you may not get created/deleted notifications for other files in the same directory. +If you load only a single file in a directory using `VirtualFile.findChild()`, you will get notifications for changes to that file, but you may not get created/deleted notifications for other files in the same directory. diff --git a/topics/basics/disposers.md b/topics/basics/disposers.md index dc3b21ea06b..fad20ff1f06 100644 --- a/topics/basics/disposers.md +++ b/topics/basics/disposers.md @@ -7,7 +7,7 @@ The IntelliJ Platform's [`Disposer`](%gh-ic%/platform/util/src/com/intellij/openapi/util/Disposer.java) facilitates resource cleanup. If a subsystem keeps a set of resources alive coincidently with a parent object's lifetime, the subsystem's resources should be registered with the `Disposer` to be released before or at the same time as the parent object. -The most common resource type managed by `Disposer` is listeners, but there are other possible types: +Listeners are the most common resource type managed by `Disposer`, but there are other possible types: * File handles, and database connections, * Caches and other significant data structures. diff --git a/topics/basics/getting_started/build_number_ranges.md b/topics/basics/getting_started/build_number_ranges.md index c1a30c04919..79dacc52170 100644 --- a/topics/basics/getting_started/build_number_ranges.md +++ b/topics/basics/getting_started/build_number_ranges.md @@ -50,7 +50,7 @@ For example, `232.*` for all 2023.2.x releases. To denote a release, a multipart build number is used. It consists of the following parts: -* Product ID (`IC` for IDEA Community, `IU` for IDEA Ultimate, `RM` for RubyMine, `PY` for PyCharm, `PS` for PhpStorm, etc.) +* Product ID (`IU` for IDEA Ultimate, `RM` for RubyMine, `PY` for PyCharm, `PS` for PhpStorm, etc.) * Branch number (`223`) * Build number in the branch (`9559`) diff --git a/topics/basics/getting_started/plugin/developing_plugins.md b/topics/basics/getting_started/plugin/developing_plugins.md index 352ac9df025..c1a95fa5b5d 100644 --- a/topics/basics/getting_started/plugin/developing_plugins.md +++ b/topics/basics/getting_started/plugin/developing_plugins.md @@ -4,7 +4,7 @@ Develop an IntelliJ Platform plugin using Gradle and Gradle IntelliJ Plugin. -IntelliJ Platform plugins can be developed by using either [IntelliJ IDEA Community Edition](https://www.jetbrains.com/idea/download/) or [IntelliJ IDEA Ultimate](https://www.jetbrains.com/idea/download/) as your IDE. +IntelliJ Platform plugins can be developed by using [IntelliJ IDEA](https://www.jetbrains.com/idea/download/) as your IDE. It is highly recommended to always use the latest available version, as the plugin development tooling support from _Plugin DevKit_ continues supporting new features. Before starting with the actual development, make sure to understand all requirements to achieve best [](plugin_user_experience.md). @@ -20,7 +20,7 @@ a dedicated Gradle plugin: -The IntelliJ IDEA Ultimate and Community editions provide the necessary plugins to support Gradle-based plugin development: _Gradle_ and _Plugin DevKit_. +The IntelliJ IDEA provides the necessary plugins to support Gradle-based plugin development: _Gradle_ and _Plugin DevKit_. To verify these plugins are installed and enabled, see the help section about [Managing Plugins](https://www.jetbrains.com/help/idea/managing-plugins.html). diff --git a/topics/basics/getting_started/theme/setting_up_theme_environment.md b/topics/basics/getting_started/theme/setting_up_theme_environment.md index 45e57e315d1..904be8d98ec 100644 --- a/topics/basics/getting_started/theme/setting_up_theme_environment.md +++ b/topics/basics/getting_started/theme/setting_up_theme_environment.md @@ -1,6 +1,6 @@ -# Setting Up a Development Environment + - +# Setting Up a Development Environment Setting up a development environment required for developing a theme. @@ -10,9 +10,9 @@ Use the following checklist to ensure that you are ready to develop your custom theme: -1. **[IntelliJ IDEA Community Edition](https://www.jetbrains.com/idea/download/)** or **[IntelliJ IDEA Ultimate](https://www.jetbrains.com/idea/download/)** is installed. +1. **[IntelliJ IDEA](https://www.jetbrains.com/idea/download/)** is installed. 2. **Plugin DevKit** plugin is installed and [enabled in IntelliJ IDEA](https://www.jetbrains.com/help/idea/managing-plugins.html). -3. **IntelliJ IDEA CE source code** is checked-out. _(Optional)_ +3. **IntelliJ IDEA CE source code** is checked out. _(Optional)_ This step is needed only when you plan to debug the IntelliJ Platform code. See [](#get-intellij-idea-ce-source-code) for more details. @@ -25,18 +25,18 @@ Use the following checklist to ensure that you are ready to develop your custom Getting the IntelliJ IDEA CE source code is not a requirement for theme development as debugging the platform code while developing a theme is a rare situation. In case you are developing a plugin extending IDE behavior, or you need to understand how some components work internally, having sources makes debugging much more straightforward. -For detailed instructions on how to check out the code efficiently, refer to the _Getting IntelliJ IDEA Community Edition Source Code_ section of [IntelliJ IDEA Community Edition README file](%gh-ic%/README.md). +For detailed instructions on how to check out the code efficiently, refer to the _Getting IntelliJ Platform_ section of the [IntelliJ Platform README file](%gh-ic%/README.md). Note that building the checked-out sources is not required in this case. ## Configuring IntelliJ Platform Plugin SDK -> For more information about SDKs, see [SDKs section](https://www.jetbrains.com/help/idea/working-with-sdks.html) in the IntelliJ IDEA Web Help. +> For more information about SDKs, see the [SDKs section](https://www.jetbrains.com/help/idea/working-with-sdks.html) in the IntelliJ IDEA Web Help. ### Download IntelliJ-Based IDE -To see the effects of the developed plugin in real IDE, it is required to run the plugin in an [](ide_development_instance.md). -In most cases, it is enough to download and use _[IntelliJ IDEA](https://www.jetbrains.com/idea/download/) Community Edition_. -If it is required to style components used only in a specific IDE like _IntelliJ IDEA Ultimate_ or _WebStorm_, they can also be used as SDK, but debugging the core code will only work with the _IntelliJ IDEA Community Edition_. +To see the effects of the developed plugin in a real IDE, it is required to run the plugin in an [IDE development instance](ide_development_instance.md). +In most cases, it is enough to download and use _[IntelliJ IDEA](https://www.jetbrains.com/idea/download/)_. +If it is required to style components used only in a specific IDE like _GoLand_ or _WebStorm_, they can also be used as SDK, but debugging the core code will only work with the _IntelliJ IDEA_. ### Add JDK and IntelliJ Platform Plugin SDK @@ -62,9 +62,13 @@ The second step is adding IntelliJ Platform Plugin SDK that will use the JDK con 1. Go to File | Project Structure | Platform Settings | SDKs. 2. Click the Add button (+). -3. Select the Add IntelliJ Platform Plugin SDK... option. -4. Choose the installation folder of the IDE [downloaded previously](#download-intellij-based-ide) (on macOS, select application icon in /Applications/). -5. In the Select Internal Java Platform dialog, select the JDK configured in the [previous step](#add-jdk) and click OK button. +3. Select the Add IntelliJ Platform Plugin SDK from disk... option. +4. Choose the installation folder of the IDE [downloaded previously](#download-intellij-based-ide). + > On macOS, in the file chooser, select /Applications/ and switch the view to Show items as: List. + > Then, expand the IDE item and select the Contents folder. + > + {style="tip"} +5. In the Select Internal Java Platform dialog, select the JDK configured in the [previous step](#add-jdk) and click the OK button. 6. In the added SDK, specify the Sandbox Home directory. See [](ide_development_instance.md#the-development-instance-sandbox-directory) for details. diff --git a/topics/basics/getting_started/theme/themes_customize.md b/topics/basics/getting_started/theme/themes_customize.md index 46a7fa20fa0..5ad5297f33d 100644 --- a/topics/basics/getting_started/theme/themes_customize.md +++ b/topics/basics/getting_started/theme/themes_customize.md @@ -316,3 +316,20 @@ The Laf Defaults inspector will prompt with a list of UI Control keys and their If an inspected component can be styled with the UI control key, it will include its name, for example: ![UI Inspector Key Names](ui_inspector_key_names.png){width="710"} + +## Extending Themes + +A new theme can be based on an existing theme and inherit its customizations. +To define a parent there, in the root of a theme description file, add: +```json +{ + ... + "parentTheme": "ParentThemeId", + ... +} +``` +The parent theme's ID is the `id` attribute of the `themeProvider` element registered in the plugin.xml file, for example: + +```xml + +``` diff --git a/topics/basics/getting_started/theme/themes_getting_started.md b/topics/basics/getting_started/theme/themes_getting_started.md index 673f74189ca..37b1e4bb0fd 100644 --- a/topics/basics/getting_started/theme/themes_getting_started.md +++ b/topics/basics/getting_started/theme/themes_getting_started.md @@ -20,12 +20,12 @@ The [themes available for download](https://plugins.jetbrains.com/search?headlin ## Theme Plugin Development -Themes can be developed by using either [IntelliJ IDEA Community Edition](https://www.jetbrains.com/idea/download/) or [IntelliJ IDEA Ultimate](https://www.jetbrains.com/idea/download/) as your IDE (it is highly recommended to use the latest available version). +Themes can be developed by using [IntelliJ IDEA](https://www.jetbrains.com/idea/download/) as your IDE (it is highly recommended to use the latest available version). Both include the complete set of development tools required to develop theme plugins. To become more familiar with IntelliJ IDEA, please refer to the [IntelliJ IDEA Web Help](https://www.jetbrains.com/idea/help/). A theme is one of the [plugin types](plugin_types.md#themes). -Its structure doesn't significantly differ from plugins extending IDE behavior, and can be implemented by using one of the supported approaches: _DevKit_ or _Gradle_. +Its structure doesn't significantly differ from plugins extending IDE behavior and can be implemented by using one of the supported approaches: _DevKit_ or _Gradle_. The choice of the development approach depends on the project requirements and developer's experience. ### DevKit-Based Theme Project diff --git a/topics/basics/indexing_and_psi_stubs/stub_indexes.md b/topics/basics/indexing_and_psi_stubs/stub_indexes.md index 5581d4e617e..3a825e5c260 100644 --- a/topics/basics/indexing_and_psi_stubs/stub_indexes.md +++ b/topics/basics/indexing_and_psi_stubs/stub_indexes.md @@ -39,7 +39,7 @@ The following steps need to be performed only once for each language that suppor See [`StubElementTypeHolderEP`](%gh-ic%/platform/core-api/src/com/intellij/psi/stubs/StubElementTypeHolderEP.java) docs for important requirements. **Examples:** -- [`JavaStubElementTypes`](%gh-ic%/java/java-psi-impl/src/com/intellij/psi/impl/java/stubs/JavaStubElementTypes.java) registered in [`JavaPsiPlugin.xml`](%gh-ic%/java/java-psi-impl/resources/META-INF/JavaPsiPlugin.xml) +- [`JavaStubElementTypes`](%gh-ic%/java/java-psi-impl/src/com/intellij/psi/impl/java/stubs/JavaStubElementTypes.java) registered in [`intellij.java.psi.impl.xml`](%gh-ic%/java/java-psi-impl/resources/intellij.java.psi.impl.xml) - see [`Angular2MetadataElementTypes`](%gh-ij-plugins%/Angular/src/org/angular2/entities/metadata/Angular2MetadataElementTypes.kt) for Kotlin sample @@ -48,12 +48,12 @@ The following steps need to be performed only once for each language that suppor For each element type that needs to be stored in the stub tree, perform the following steps: -1. Define an interface for the stub, derived from the [`StubElement`](%gh-ic%/platform/core-api/src/com/intellij/psi/stubs/StubElement.java) interface ([example](%gh-ic%/plugins/properties/properties-psi-api/src/com/intellij/lang/properties/psi/PropertyStub.java)). -2. Provide an implementation for the interface ([example](%gh-ic%/plugins/properties/properties-psi-impl/src/com/intellij/lang/properties/psi/impl/PropertyStubImpl.java)). -3. Make sure the interface for the PSI element extends [`StubBasedPsiElement`](%gh-ic%/platform/core-api/src/com/intellij/psi/StubBasedPsiElement.java) parameterized by the type of the stub interface ([example](%gh-ic%/plugins/properties/properties-psi-api/src/com/intellij/lang/properties/psi/Property.java)). -4. Make sure the implementation class for the PSI element extends [`StubBasedPsiElementBase`](%gh-ic%/platform/core-impl/src/com/intellij/extapi/psi/StubBasedPsiElementBase.java) parameterized by the type of the stub interface ([example](%gh-ic%/plugins/properties/properties-psi-impl/src/com/intellij/lang/properties/psi/impl/PropertyImpl.java)). +1. Define an interface for the stub, derived from the [`StubElement`](%gh-ic%/platform/core-api/src/com/intellij/psi/stubs/StubElement.java) interface ([example](%gh-ic-251-master%/plugins/properties/properties-psi-api/src/com/intellij/lang/properties/psi/PropertyStub.java)). +2. Provide an implementation for the interface ([`example`](%gh-ic-master%/plugins/properties/properties-common/src/com/intellij/lang/properties/psi/impl/PropertyStubImpl.java)). +3. Make sure the interface for the PSI element extends [`StubBasedPsiElement`](%gh-ic%/platform/core-api/src/com/intellij/psi/StubBasedPsiElement.java) parameterized by the type of the stub interface ([example](%gh-ic-251-master%/plugins/properties/properties-psi-api/src/com/intellij/lang/properties/psi/Property.java)). +4. Make sure the implementation class for the PSI element extends [`StubBasedPsiElementBase`](%gh-ic%/platform/core-impl/src/com/intellij/extapi/psi/StubBasedPsiElementBase.java) parameterized by the type of the stub interface ([`example`](%gh-ic-251-master%/plugins/properties/properties-psi-impl/src/com/intellij/lang/properties/psi/impl/PropertyImpl.java)). Provide both a constructor that accepts an `ASTNode` and a constructor that accepts a stub. -5. Create a class that implements [`IStubElementType`](%gh-ic%/platform/core-api/src/com/intellij/psi/stubs/IStubElementType.java) and is parameterized with the stub interface and the actual PSI element interface ([example](%gh-ic%/plugins/properties/properties-psi-impl/src/com/intellij/lang/properties/parsing/PropertyStubElementType.java)). +5. Create a class that implements [`IStubElementType`](%gh-ic%/platform/core-api/src/com/intellij/psi/stubs/IStubElementType.java) and is parameterized with the stub interface and the actual PSI element interface ([example](%gh-ic-251-master%/plugins/properties/properties-psi-impl/src/com/intellij/lang/properties/parsing/PropertyStubElementType.java)). Implement the `createPsi()` and `createStub()` methods for creating PSI from a stub and vice versa. Implement the `serialize()` and `deserialize()` methods for storing the data in a binary stream. @@ -61,8 +61,8 @@ For each element type that needs to be stored in the stub tree, perform the foll For always-leaf stub nodes return `true` from `isAlwaysLeaf()` (2023.3). "Container" stubs that do not serialize any data of their own may implement [`EmptyStubSerializer`](%gh-ic%/platform/core-api/src/com/intellij/psi/stubs/EmptyStubSerializer.java) to optimize storage (2023.3). -6. Use the class implementing `IStubElementType` as the element type constant when parsing ([example](%gh-ic%/plugins/properties/properties-psi-impl/src/com/intellij/lang/properties/parsing/PropertiesElementTypes.java)). -7. Make sure all methods in the PSI element interface access the stub data rather than the PSI tree when appropriate ([example: `Property.getKey()` implementation](%gh-ic%/plugins/properties/properties-psi-impl/src/com/intellij/lang/properties/psi/impl/PropertyImpl.java)). +6. Use the class implementing `IStubElementType` as the element type constant when parsing ([`example`](%gh-ic-251-master%/plugins/properties/properties-psi-impl/src/com/intellij/lang/properties/parsing/PropertiesElementTypes.java)). +7. Make sure all methods in the PSI element interface access the stub data rather than the PSI tree when appropriate ([example: `Property.getKey()` implementation](%gh-ic-251-master%/plugins/properties/properties-psi-impl/src/com/intellij/lang/properties/psi/impl/PropertyImpl.java)). diff --git a/topics/basics/intellij_coding_guidelines.md b/topics/basics/intellij_coding_guidelines.md index 9d32cdbce5f..77502ca12bc 100644 --- a/topics/basics/intellij_coding_guidelines.md +++ b/topics/basics/intellij_coding_guidelines.md @@ -29,11 +29,11 @@ We're generally pretty lax about code formatting, but at least the following con - Use `my` prefix for instance variables and `our` prefix for class variables. - New source code files must include a copyright statement with the Apache 2 license and the name of the contributor. -The easiest way to follow our code formatting guidelines is to reformat your code submissions using the shared code style, which is included in the IntelliJ IDEA Community Edition project directory. +The easiest way to follow our code formatting guidelines is to reformat your code submissions using the shared code style, which is included in the IntelliJ IDEA project directory. ## Inspections -The IntelliJ IDEA Community Edition project includes a shared inspection profile. +The IntelliJ IDEA project includes a shared inspection profile. We strongly recommend making sure that the code you submit does not contain any warnings highlighted by the inspections configured in that inspection profile. ## Javadoc Comments diff --git a/topics/basics/platform_contributions.md b/topics/basics/platform_contributions.md index 5cbd089e442..c4b9db8d810 100644 --- a/topics/basics/platform_contributions.md +++ b/topics/basics/platform_contributions.md @@ -18,10 +18,10 @@ The forums are an excellent source for users and contributors interested in havi The success of any open-source project depends on the number of people who use the product and contribute back to the project. By linking to [](https://www.jetbrains.com/opensource/idea), you can increase the chances of a new user or contributor finding out about the project and joining the community. -If you're as excited about IntelliJ IDEA Community Edition as we are, you can show it by linking to us. +If you're as excited about IntelliJ IDEA as we are, you can show it by linking to us. Project logos and other assets are [also available](https://www.jetbrains.com/company/brand/logos/). -### Promote IntelliJ Platform and IntelliJ IDEA Community Edition +### Promote IntelliJ Platform Help promote the platform and IDE by using your blog, Twitter, Facebook, or submitting an article to your favorite local magazine. If you are a member of a different open-source community, why not mention IntelliJ IDEA on their discussion forums or at conferences? @@ -66,7 +66,7 @@ When writing a plugin, you have control over the code and don't need to sign the ### Submit a Patch -If you would like to improve the code in the IntelliJ Platform or the core functionality of IntelliJ IDEA, you can submit a pull request to the [IntelliJ IDEA Community Edition repository on GitHub](%gh-ic%/README.md). +If you would like to improve the code in the IntelliJ Platform or the core functionality of IntelliJ IDEA, you can submit a pull request to the [IntelliJ Platform repository on GitHub](%gh-ic%/README.md). When preparing the change, please make sure to follow the [](intellij_coding_guidelines.md). A developer will review your contribution and, if it meets the quality criteria and fits well with the rest of the code, you'll be notified about the acceptance of the patch. diff --git a/topics/basics/plugin_alternatives.md b/topics/basics/plugin_alternatives.md index d7db6736a01..12cdcf2c378 100644 --- a/topics/basics/plugin_alternatives.md +++ b/topics/basics/plugin_alternatives.md @@ -10,6 +10,19 @@ If you need a functionality that is specific to your project domain, conventions Before you start the IntelliJ Platform plugin development, define your requirements and verify if they can be covered with any of the alternatives described below. Consider implementing an actual plugin only when the described solutions are insufficient in your case and there is a significant number of developers who can benefit from it. +## Kotlin Notebook Integration + + +[](tools_kotlin_notebook.md) offers an interactive environment for testing IntelliJ Platform APIs directly within your IDE. By declaring `%use intellij-platform` in a notebook cell and switching to "Run in IDE Process" mode, you can run IntelliJ Platform code within the active IDE runtime without needing to create a full plugin project. + +This integration is especially helpful for: +- Quickly prototyping IDE features and UI components +- Testing platform APIs and behaviors +- Building interactive documentation and tutorials +- Trying out plugin ideas before formal development + +The notebook environment provides direct access to the IntelliJ Platform APIs, UI rendering features, resource management via the Disposer mechanism, and the ability to load and interact with installed plugins. + ## Structural Search and Replace Inspections The [Structural Search and Replace (SSR)](https://www.jetbrains.com/help/idea/structural-search-and-replace.html) functionality allows defining search patterns which are based not only on textual information but also on the structure of the searched code fragments, no matter how it is formatted or commented. diff --git a/topics/basics/plugin_structure/modular_plugins.md b/topics/basics/plugin_structure/modular_plugins.md new file mode 100644 index 00000000000..f232303fd4a --- /dev/null +++ b/topics/basics/plugin_structure/modular_plugins.md @@ -0,0 +1,102 @@ + + +# Modular Plugins (Experimental) + + +Splitting plugin by modules to support remote development and other cases + +A regular plugin has a single [class loader](plugin_class_loaders.md) which is used to load all classes of the plugin. +This approach works well for many plugins, but there are cases when more granularity is needed: +* To properly work in remote development mode, different parts of the plugin should be loaded in the backend and the frontend processes; these parts have different dependencies. +* If some classes of a plugin `A` depend on classes from a plugin `B`, they should be loaded by a separate class loader to allow unloading the plugin `B` without restarting the IDE. + +In such cases, it's possible to use the new modular plugin format: Plugin Model Version 2. + +> The new format is still experimental and may change in the future. +> It's not recommended to use it for cases other than writing plugins for remote development where the new format is required. +> +> Modular plugins can be developed only with [](tools_intellij_platform_gradle_plugin.md). +> +{style="note"} + +## Plugin Modules + +A plugin consists of one or more modules registered in the `content` tag in the [plugin descriptor file](plugin_configuration_file.md): + +```xml + + + + + +``` + +The name of the module is specified by a required `name` attribute and must be unique within the plugin. + +When the IntelliJ Platform loads a plugin, it tries to load all its modules. +A module can be loaded if and only if all its dependencies are available. +If some module cannot be loaded, the behavior depends on the value of an optional `loading` attribute: +* `required`: module is the required part of the plugin; if the module cannot be loaded, the whole plugin isn't loaded, and an error is shown to the user. +* `optional`: module is an optional part of the plugin; if the module cannot be loaded, it is skipped and doesn't prevent other modules from the plugin from being loaded. +* other options are currently for internal use only. + +If the `loading` attribute is not specified, the module is treated as optional by default. + +If the module is optional, it's possible to specify that it should be treated as required when the IDE is running in a specific mode via the `required-if-available` attribute: +* `intellij.platform.backend`: the module is required if the current process is a regular IDE process, or it's a remote development backend process; +* `intellij.platform.frontend`: the module is required if the current process is a regular IDE process, or it's a remote development frontend process (JetBrains Client). + +Source code and resource files of modules must be located in separate Gradle projects registered in the main module as [submodules](tools_intellij_platform_gradle_plugin_plugins.md#module). + +## Module Descriptor File + +A module must have a descriptor file with the name equal to the module name and xml extension (for example, example.my.module.xml, located directly in the main/resources directory of the corresponding Gradle project (**not in** META-INF directory!). + +The module descriptor file uses the same format as the [plugin configuration file](plugin_configuration_file.md), but only the following top-level tags are allowed: +* `` +* `` +* `` +* `` +* `` +* `` + +The `` tag is also not allowed. +A special `` tag can be used to specify dependencies on other modules and plugins: + +```xml + + + + +``` + +`` subtag specifies dependency on another module with the given name. +`` subtag specifies dependency on a regular (classic) plugin with the given ID. +Dependencies are used at runtime to determine whether a module can be loaded or not, and to configure the class loader of the module. + +Like with `` tags in regular plugins, it's necessary to specify [dependencies in the Gradle build script](plugin_dependencies.md#intellij-platform-gradle-plugin-2x) as well to have them in the compilation classpath. + +If no dependencies are specified, the module will always be loaded when the plugin is loaded, regardless of the current IDE and the mode it runs in. + +### Class Loaders + +Each module has its own class loader. +The class loader has class loaders of modules and plugins specified in `` tag of the module descriptor as its parents, so it delegates loading of classes to them if they aren't found in the module itself. +Also, the core class loader of the IntelliJ Platform is automatically added as a parent class loader. + +If a regular (classic) plugin declares a dependency on a modular plugin using `` tag, class loaders of all plugin modules will be added as parent class loaders. + +## Plugin Configuration File + +The plugin configuration file for modular plugins uses the same format as a [plugin configuration file for regular (classic) plugins](plugin_configuration_file.md). +However, the following top-level tags related to registration of classes aren't allowed in it; they must be located in the module descriptor files where the referenced classes are defined: +* `` +* `` +* `` +* `` +* `` + +Also, `` tags are not allowed. +Dependencies must be specified in the module descriptor files using `` tag. +The IDE will automatically treat dependencies of modules marked as 'required' as necessary dependencies of the plugin and will suggest installing or enabling corresponding plugins when the plugin is being installed. diff --git a/topics/basics/plugin_structure/plugin_configuration_file.md b/topics/basics/plugin_structure/plugin_configuration_file.md index db1fbff5075..2f2e0fa5c72 100644 --- a/topics/basics/plugin_structure/plugin_configuration_file.md +++ b/topics/basics/plugin_structure/plugin_configuration_file.md @@ -283,10 +283,22 @@ Attributes - `since-build` _(**required**)_
    The lowest IDE version compatible with the plugin. - `until-build` _(optional)_
    - - The highest IDE version compatible with the plugin. - Undefined value declares compatibility with all the IDEs since the version specified by the `since-build` - (also with the future builds that may cause incompatibility errors). + The highest version of the IDE the plugin is compatible with. + It's highly recommended not to set this attribute, so the plugin will be compatible with all IDE versions since the + version specified by the `since-build`.
    + If it becomes necessary to specify the highest compatible IDE version later, it'll be possible to do that via JetBrains + Marketplace.
    + Only if the publishing process for the plugin is configured to upload a new version for each major IDE version, it makes + sense to limit the highest compatible IDE version from the beginning. + In that case, use `strict-until-build` instead. +- `strict-until-build` _(optional; available since 2025.3)_
    + + The highest version of the IDE the plugin is compatible with.
    + Use this attribute only if the publishing process for the plugin is configured to upload a new version for each major + IDE version. + Otherwise, skip this attribute.
    + If it becomes necessary to specify the highest compatible IDE version later, it'll be possible to do that via + JetBrains Marketplace. Examples : @@ -469,12 +481,6 @@ Examples ```xml com.intellij.modules.java ``` -- Optional plugin dependency: - ```xml - - com.example.dependencypluginid - - ``` - Required module dependency with additional configuration: ```xml -**Reference:** [Declaring Incompatibility with Module](plugin_compatibility.md#declaring-incompatibility-with-module) +**Reference:** [Declaring Incompatibility with Plugin](plugin_compatibility.md#declaring-incompatibility-with-module) -Declares incompatibility with a provided module. +The [ID](#idea-plugin__id) or alias of the plugin the current plugin is incompatible with. +The plugin is not loaded if the incompatible plugin is installed in the current IDE. {type="narrow"} Required : no; ignored in an [additional config file](#additional-plugin-configuration-files) -Example +Examples : - ```xml - - com.intellij.modules.appcode.ide - - ``` +- Incompatibility with the Java plugin: + ```xml + + com.intellij.java + + ``` +- Incompatibility with the AppCode plugin referenced via its alias: + ```xml + + com.intellij.modules.appcode.ide + + ``` ### `extensions` {#idea-plugin__extensions} @@ -592,7 +606,7 @@ Attributes `order`.
    To not clash with other plugins defining extensions with the same identifier, - consider prepending the identifier with a prefix related to the plugin [``](#idea-plugin__id) or + consider prepending the identifier with a prefix related to the plugin [``](#idea-plugin__id) or [``](#idea-plugin__name), for example, `id="com.example.myplugin.myExtension"`. - `order` _(optional)_
    Allows for ordering the extension relative to other instances of the same extension point. @@ -616,7 +630,7 @@ Attributes - `mac` - `unix` - `windows` - + For example, `os="windows"` registers the extension on Windows only. ### `extensionPoints` @@ -694,12 +708,12 @@ Attributes The scope in which the [extension](plugin_extensions.md) is instantiated. - + Allowed values: - `IDEA_APPLICATION` _(default)_ - `IDEA_PROJECT` - `IDEA_MODULE` (**deprecated**) - + **It is strongly recommended not to introduce new project- and module-level extension points.** If an extension point needs to operate on a `Project` or `Module` instance, declare an application-level extension point and pass the instance as a method parameter. @@ -742,7 +756,7 @@ Example An extension point which restricts the type provided in a `myClass` attribute to be an instance of `com.example.ParentType`, and the type provided in a `someClass` element to be an instance of `java.lang.Comparable`: - + ```xml ``` - + When using the above extension point, an implementation could be registered as follows: - + ```xml com.example.MyComparable ``` - + where: - + - `com.example.MyCustomType` must be a subtype of `com.example.ParentType` - `com.example.MyComparable` must be a subtype of `java.lang.Comparable` @@ -1492,7 +1506,7 @@ Children Example : Given a plugin descriptor: - + ```xml com.example.myplugin @@ -1501,18 +1515,18 @@ Example ... ``` - + and /META-INF/another-plugin.xml: - + ```xml ... ... ``` - + The effective plugin descriptor loaded to memory will contain the following elements: - + ```xml com.example.myplugin diff --git a/topics/basics/plugin_structure/plugin_dependencies.md b/topics/basics/plugin_structure/plugin_dependencies.md index 1887570d6e7..1cddcc266b1 100644 --- a/topics/basics/plugin_structure/plugin_dependencies.md +++ b/topics/basics/plugin_structure/plugin_dependencies.md @@ -87,23 +87,24 @@ See also [](plugin_compatibility.md#modules-specific-to-functionality). -| Plugin Name | Plugin ID | Related Documentation | -|---------------------------|---------------------------------|----------------------------------------------------------------------------------| -| Copyright | `com.intellij.copyright` | | -| CSS | `com.intellij.css` | [](webstorm.md) | -| Database Tools and SQL | `com.intellij.database` | [](data_grip.md) | -| Gradle | `com.intellij.gradle` | | -| Groovy | `org.intellij.groovy` | | -| IntelliLang | `org.intellij.intelliLang` | [](language_injection.md) | -| Java | `com.intellij.java` | [](idea.md#java-plugin) | -| JavaScript and TypeScript | `JavaScript` | [](webstorm.md) | -| JSON | `com.intellij.modules.json` | [JSON plugin introduction notes](api_changes_list_2024.md#json-plugin-new-20243) | -| Kotlin | `org.jetbrains.kotlin` | [](idea.md#kotlin-plugin) | -| Markdown | `org.intellij.plugins.markdown` | | -| Maven | `org.jetbrains.idea.maven` | | -| Spring | `com.intellij.spring` | [](spring_api.md) | -| Spring Boot | `com.intellij.spring.boot` | [](spring_api.md#spring-boot) | -| YAML | `org.jetbrains.plugins.yaml` | | +| Plugin Name | Plugin ID | Related Documentation | +|---------------------------|----------------------------------|----------------------------------------------------------------------------------| +| Copyright | `com.intellij.copyright` | | +| CSS | `com.intellij.css` | [](webstorm.md) | +| Database Tools and SQL | `com.intellij.database` | [](data_grip.md) | +| Gradle | `com.intellij.gradle` | | +| Groovy | `org.intellij.groovy` | | +| IntelliLang | `org.intellij.intelliLang` | [](language_injection.md) | +| Java | `com.intellij.java` | [](idea.md#java-plugin) | +| JavaScript and TypeScript | `JavaScript` | [](webstorm.md) | +| JSON | `com.intellij.modules.json` | [JSON plugin introduction notes](api_changes_list_2024.md#json-plugin-new-20243) | +| Kotlin | `org.jetbrains.kotlin` | [](idea.md#kotlin-plugin) | +| Markdown | `org.intellij.plugins.markdown` | | +| Maven | `org.jetbrains.idea.maven` | | +| Spring | `com.intellij.spring` | [](spring_api.md) | +| Spring Boot | `com.intellij.spring.boot` | [](spring_api.md#spring-boot) | +| Terminal | `org.jetbrains.plugins.terminal` | [](embedded_terminal.md) | +| YAML | `org.jetbrains.plugins.yaml` | | ### Preparing Sandbox diff --git a/topics/basics/plugin_structure/plugin_extensions.md b/topics/basics/plugin_structure/plugin_extensions.md index 4cadf3181df..3bed00a1b31 100644 --- a/topics/basics/plugin_structure/plugin_extensions.md +++ b/topics/basics/plugin_structure/plugin_extensions.md @@ -8,7 +8,11 @@ Declaring extensions in plugins to customize the IDE's behavior and functionalit Extensions are the most common way of customizing functionality in the IDE. -_Extensions_ are the most common way for a plugin to extend the IntelliJ Platform's functionality in a way that is not as straightforward as adding an action to a menu or toolbar. +_Extensions_ are the most common way for a plugin to extend the IntelliJ-based IDE's functionality. +They are implementations of specific interfaces or classes that are [registered](#declaring-extensions) in the plugin descriptor. +Provided extension implementations are called by the platform or other plugins to customize and extend the IDE's functionality. + +## Common Extension Use Cases The following are some of the most common tasks achieved using extensions: diff --git a/topics/basics/project_view.md b/topics/basics/project_view.md index e197893503d..76b614bdc5e 100644 --- a/topics/basics/project_view.md +++ b/topics/basics/project_view.md @@ -19,7 +19,7 @@ This is used to, e.g., change the icon of module nodes to reflect the module typ to Python Jupyter directories as location strings. To modify project view node representations, implement -[`ProjectViewNodeDecorator`](%gh-ic%/platform/lang-impl/src/com/intellij/ide/projectView/ProjectViewNodeDecorator.java) +[`ProjectViewNodeDecorator`](%gh-ic%/platform/lang-impl/src/com/intellij/ide/projectView/ProjectViewNodeDecorator.kt) and register it in the . From the interface only the `decorate()` method that modifies `ProjectViewNode`s needs to be implemented. diff --git a/topics/basics/settings.md b/topics/basics/settings.md index 84e1cce2f56..53e7f8b9c73 100644 --- a/topics/basics/settings.md +++ b/topics/basics/settings.md @@ -14,7 +14,7 @@ Configure and persist preferences of IntelliJ Platform plugins with the settings -Settings are but one application of the IntelliJ Platform [Persistence Model](persistence.md). +Settings are one of the applications of the IntelliJ Platform's [Persistence Model](persistence.md). * [](settings_guide.md) for information about Settings Extension Points and implementations. * [](settings_groups.md) for information about creating custom Settings groups and parent-child relationships. diff --git a/topics/basics/testing_plugins/integration_tests/integration_tests_intro.md b/topics/basics/testing_plugins/integration_tests/integration_tests_intro.md index eeb050c4f75..4247b42bfab 100644 --- a/topics/basics/testing_plugins/integration_tests/integration_tests_intro.md +++ b/topics/basics/testing_plugins/integration_tests/integration_tests_intro.md @@ -116,13 +116,13 @@ Starter.newContext( The Context object stores IDE runtime configuration: -* IDE type (e.g., IntelliJ Community, PhpStorm, GoLand). +* IDE type (e.g., IntelliJ IDEA, PhpStorm, GoLand). * IDE version (2024.3 in this example). * Project configuration (using `NoProject` for this example). * Custom VM options, paths, and SDK settings. The `testName` parameter defines the folder name for test artifacts, which is useful when running multiple IDE instances in a single test. -The test case uses IntelliJ IDEA Community Edition version 2024.3, and starts the IDE without any project, so the welcome screen will be shown. +The test case uses IntelliJ IDEA version 2024.3, and starts the IDE without any project, so the welcome screen will be shown. ### 2. Plugin Installation diff --git a/topics/basics/testing_plugins/testing_faq.md b/topics/basics/testing_plugins/testing_faq.md index 5f95807525f..82bb891ec2b 100644 --- a/topics/basics/testing_plugins/testing_faq.md +++ b/topics/basics/testing_plugins/testing_faq.md @@ -161,7 +161,7 @@ Use [`DefaultLogger.disableStderrDumping()`](%gh-ic%/platform/util/src/com/intel ### How to register a resource (DTD, XSD) temporarily? -Use [`ExternalResourceManagerExImpl.registerResourceTemporarily()`](%gh-ic%/xml/xml-psi-impl/src/com/intellij/javaee/ExternalResourceManagerExImpl.kt) passing `getTestRootDisposable()`. +Use [`ExternalResourceManagerExImpl.registerResourceTemporarily()`](%gh-ic%/xml/impl/src/com/intellij/javaee/ExternalResourceManagerExImpl.kt) passing `getTestRootDisposable()`. ### How to replace a component/service in tests? @@ -184,10 +184,9 @@ Use [`WaitFor`](%gh-ic%/platform/util/src/com/intellij/util/WaitFor.java). Plugins supporting a JVM language may require JDK and language standard library to be set up in a test project, so that classes like `java.lang.String` can be correctly resolved during tests. Tests extending [`LightJavaCodeInsightFixtureTestCase`](%gh-ic%/java/testFramework/src/com/intellij/testFramework/fixtures/LightJavaCodeInsightFixtureTestCase.java) use one of the mock JDKs in the [Java plugin](%gh-ic%/java) sources (notice mockJDK-\$JAVA_VERSION\$ directories). -These JAR files are not available in plugin project dependencies, so the IntelliJ Community sources must be checked out to the machine running the tests, and sources' location must be provided to the test framework. +These JAR files are not available in plugin project dependencies, so the IntelliJ Platform sources must be checked out to the machine running the tests, and sources' location must be provided to the test framework. It's done by setting the `idea.home.path` system property to the absolute path of the checked-out sources in the `test` task configuration: - diff --git a/topics/intro/content_updates.md b/topics/intro/content_updates.md index 5c4bc180525..b9a90791530 100644 --- a/topics/intro/content_updates.md +++ b/topics/intro/content_updates.md @@ -12,6 +12,68 @@ See [GitHub Changelog](https://github.com/JetBrains/intellij-sdk-docs/commits/ma ## 2025 +### November +{#november-25} + +Terminal API +: Add a new section about [extending the Terminal](embedded_terminal.md). + +Modular Plugins +: Add a new section about [](modular_plugins.md) describing how to develop plugins ready for remote development contexts. + +Threading Kotlin Notebooks +: Link [Kotlin Notebooks](threading_model.md#kotlin-notebooks) explaining core threading model concepts. + +Minor Changes and Additions +: +- Add [](rider.md#using-custom-icons-from-the-dotnet-rider-plugin-part) Using Custom Icons from the Dotnet Rider Plugin Part. +- Update [LSP supported features](language_server_protocol.md#supported-features). + +### October +{#october-25} + +PSI Performance Introduction +: Describe why [caching get method results](psi_performance.md#overview) is important when working with PSI. + +Avoiding `idea-version@until-build` +: Add information about recommendation to [avoid using `idea-version@until-build`](plugin_configuration_file.md#idea-plugin__idea-version) for plugins. + +Minor Changes and Additions +: +- [Extending existing themes](themes_customize.md#extending-themes). +- Clarify [reacting to closing non-modal dialogs](dialog_wrapper.md#displaying-the-dialog). +- Add an [inspection code sample for Qodana](https://github.com/JetBrains/intellij-sdk-docs/tree/main/code_samples/code_inspection_qodana). +- Hide the [Kotlin UI DSL Version 1 section](kotlin_ui_dsl.md) and make [Version 2](kotlin_ui_dsl_version_2.md) the default version in content. +- Add a link to the [](threading_model.md#investigating-ui-freezes) blog post. + +### September +{#september-25} + +LSP Module Introduction +: Add information about specifying a required [dependency on the LSP module](language_server_protocol.md#pluginxml) since 2025.2.1. + +### August +{#august-25} + +Minor Changes and Additions +: +- Add information about launching coroutines from actions with [`currentThreadCoroutineScope`](launching_coroutines.md). + +### July +{#july-25} + +Kotlin Notebook integration +: Add a new section about [](tools_kotlin_notebook.md). + +Accessibility Guidelines +: Add information about making UI more [accessible](accessibility.md). + +### June +{#june-25} + +Replacement of the Web Symbol API with Poly Symbol API +: Replace the Web Symbol API documentation with [](polysymbols.md). + ### May {#may-25} @@ -97,7 +159,7 @@ Minor Changes and Additions : - How to support [grammar checks](spell_checking.md#grammar-checks) provided by Grazie plugin in custom languages. - How to provide [code vision provider](inlay_hints.md#code-vision-provider) name and description in the settings. -- How to manage [Web Symbols context](websymbols_context.md) detection. +- How to manage [Poly Symbols context](polysymbols_context.md) detection. ### April {april-24} @@ -108,7 +170,7 @@ Plugin Internationalization Minor Changes and Additions : - How to mark functionality available during indexing via [](indexing_and_psi_stubs.md#DumbAwareAPI). -- Move Extension Point and Listener Lists to the _Resources_ section and split the main _Extension Point and Listener List_ into: _IntelliJ Platform_, _IntelliJ Community Plugins_, and _Android Plugin_. +- Move Extension Point and Listener Lists to the _Resources_ section and split the main _Extension Point and Listener List_ into: _IntelliJ Platform_, _IntelliJ Platfom Plugins_, and _Android Plugin_. ### March {#march-24} @@ -203,8 +265,8 @@ Documentation ### March {#march-23} -Web Symbols -: Add [](websymbols.md) documentation, which is a framework that simplifies web technology development +Poly Symbols +: Add [](polysymbols.md) documentation, which is a framework that simplifies web technology development by utilizing the [](symbols.md) API and supporting custom syntaxes. Open Source Plugins Extension Points diff --git a/topics/intro/intellij_platform.md b/topics/intro/intellij_platform.md index 3f876f32cc5..9ec9dbdbb9e 100644 --- a/topics/intro/intellij_platform.md +++ b/topics/intro/intellij_platform.md @@ -46,10 +46,9 @@ See the [](plugins_quick_start.md) for more details. The IntelliJ Platform is Open Source, under the [Apache License](%gh-ic%/LICENSE.txt), and [hosted on GitHub](https://github.com/JetBrains/intellij-community). While this guide refers to the IntelliJ Platform as a separate entity, there is no "IntelliJ Platform" GitHub repository. -Instead, the platform is considered to be an almost complete overlap with the [IntelliJ IDEA Community Edition](idea.md), which is a free and Open Source version of IntelliJ IDEA Ultimate (the GitHub repository linked above is the [JetBrains/intellij-community](%gh-ic%/README.md) repository). -Please note: starting with the 2021.1 release, some plugins bundled with IntelliJ IDEA Community Edition are not open-source. +Instead, the platform is considered to be an almost complete overlap with the [IntelliJ Platform](idea.md) (the GitHub repository linked above is the [JetBrains/intellij-community](%gh-ic%/README.md) repository). -The version of the IntelliJ Platform is defined by the version of the corresponding IntelliJ IDEA Community Edition release. +The version of the IntelliJ Platform is defined by the version of the corresponding IntelliJ IDEA release. For example, to build a plugin against IntelliJ IDEA (2019.1.1), build #191.6707.61 means specifying the same build number tag to get the correct IntelliJ Platform files from the `intellij-community` repository. See the [](build_number_ranges.md) page for more information about build numbers corresponding to version numbering. @@ -58,9 +57,9 @@ Typically, an IDE that is based on the IntelliJ Platform will include the `intel ## IDEs Based on the IntelliJ Platform The IntelliJ Platform underlies many JetBrains IDEs. -[IntelliJ IDEA Ultimate](idea_ultimate.md) is a superset of the IntelliJ IDEA Community Edition but includes closed-source plugins ([see this feature comparison](https://www.jetbrains.com/idea/features/editions_comparison_matrix.html)). -Similarly, other products such as [WebStorm](webstorm.md) and [DataGrip](data_grip.md) are based on the IntelliJ IDEA Community Edition, but with a different set of plugins included and excluding other default plugins. -This allows plugins to target multiple products, as each product will include base functionality and a selection of plugins from the IntelliJ IDEA Community Edition repository. +[IntelliJ IDEA](idea_ultimate.md) is a superset of the IntelliJ Platform but includes closed-source plugins ([see this feature comparison](https://www.jetbrains.com/idea/features/editions_comparison_matrix.html)). +Similarly, other products such as [WebStorm](webstorm.md) and [DataGrip](data_grip.md) are based on the IntelliJ Platform, but with a different set of plugins included and excluding other default plugins. +This allows plugins to target multiple products, as each product will include base functionality and a selection of plugins from the IntelliJ Platform repository. The following IDEs are based on the IntelliJ Platform: diff --git a/topics/products/dev_alternate_products.md b/topics/products/dev_alternate_products.md index daf47fb5dac..175d39ad726 100644 --- a/topics/products/dev_alternate_products.md +++ b/topics/products/dev_alternate_products.md @@ -83,7 +83,7 @@ intellij { ### Using the IntelliJ IDEA Product Attribute If the [](tools_gradle_intellij_plugin.md) does not directly support an IntelliJ Platform-based product, the Gradle build script can still be configured to target the desired product. -In this case, the build script is configured to use IntelliJ IDEA (Community or Ultimate Edition) as the basis for the available APIs. +In this case, the build script is configured to use IntelliJ IDEA as the basis for the available APIs. This does have the drawback that APIs not specific to the target product might accidentally be included in the plugin project. However, testing the plugin project in the target product itself helps to find such mistakes. @@ -92,7 +92,7 @@ Understanding the relationship between build numbers is critical when using this * _targetIDE_ is the (version-specific) IntelliJ Platform-based IDE in which the plugin is intended to run, such as Android Studio or PhpStorm. * _baseIntelliJPlatformVersion_ is the (version-specific) IntelliJ Platform used in the build of the _targetIDE_. - The IntelliJ Platform is defined by a specific build of the IntelliJ IDEA Community Edition. + The IntelliJ Platform is defined by a specific build of the IntelliJ IDEA. The Gradle plugin attribute [`intellij.version`](configuring_plugin_project.md#intellij-platform-configuration) is set to be _baseIntelliJPlatformVersion_. For API compatibility, the IntelliJ Platform version used in the _targetIDE_ dictates the _baseIntelliJPlatformVersion_ used for developing a plugin. @@ -112,13 +112,13 @@ The version of the IntelliJ Platform used to build this product version is *BRAN If the product version isn't clear on the About screen, consult the individual product pages in _Product Specific_. The [Other IntelliJ IDEA Versions](https://www.jetbrains.com/idea/download/other.html) page is a way to find build numbers for every product version. -Additional ways include hovering over the version number for a product in [Toolbox App](https://www.jetbrains.com/toolbox-app/) or examining the About screen for IntelliJ IDEA Community. -In this example, IntelliJ IDEA Community Edition (which defines the IntelliJ Platform) for `2019.2.4` is build number `192.7142.36`. +Additional ways include hovering over the version number for a product in [Toolbox App](https://www.jetbrains.com/toolbox-app/) or examining the About screen for IntelliJ IDEA. +In this example, IntelliJ IDEA for `2019.2.4` is build number `192.7142.36`. Although the *FIX* versions are different, this is not uncommon between products, and the builds are still compatible. -The *BRANCH* and *BUILD* numbers match, therefore in this PhpStorm example: +The *BRANCH* and *BUILD* numbers match, therefore, in this PhpStorm example: * The _targetIDE_ is PhpStorm, build `192.7142.41`, -* The _baseIntelliJPlatformVersion_ (IntelliJ IDEA Community Edition) is build `192.7142.36` +* The _baseIntelliJPlatformVersion_ is build `192.7142.36` This information is used to configure the plugin project's Gradle build script and plugin.xml file. @@ -128,7 +128,7 @@ Configuring a Gradle plugin project for using _baseIntelliJPlatformVersion_ requ Changes need to be made in two places: [`intellij`](tools_gradle_intellij_plugin.md#configuration-intellij-extension) extension and [`runIde`](tools_gradle_intellij_plugin.md#tasks-runide) task. The Gradle plugin attributes describing the configuration of the [IntelliJ Platform used to build the plugin project](configuring_plugin_project.md#intellij-platform-configuration) must be explicitly set in the `intellij` task. -The [`intellij.type`](tools_gradle_intellij_plugin.md#intellij-extension-type) is `IU` because although the IntelliJ IDEA Community Edition defines the IntelliJ Platform, the PHP plugin is only compatible with IntelliJ IDEA Ultimate. +The [`intellij.type`](tools_gradle_intellij_plugin.md#intellij-extension-type) is `IU` because although the IntelliJ IDEA defines the IntelliJ Platform, the PHP plugin is only compatible with IntelliJ IDEA Ultimate. The [`intellij.version`](tools_gradle_intellij_plugin.md#intellij-extension-version) is _baseIntelliJPlatformVersion_. Any [dependencies](configuring_plugin_project.md#plugin-dependencies) on _targetIDE_-specific plugins or modules must be declared in the [`intellij`](tools_gradle_intellij_plugin.md#configuration-intellij-extension) extension. diff --git a/topics/products/goland/goland.md b/topics/products/goland/goland.md index 9334c8167fc..5bc81050b05 100644 --- a/topics/products/goland/goland.md +++ b/topics/products/goland/goland.md @@ -99,11 +99,11 @@ To see how these attributes appear in a similar Gradle build script for PhpStorm The Go plugin version is explicitly declared because it isn't bundled with IntelliJ IDEA Ultimate Edition. Select a [version](https://plugins.jetbrains.com/plugin/9568-go/versions) of the Go plugin compatible with the IntelliJ Idea Ultimate version. -| Gradle IntelliJ Plugin Attribute | Attribute Value | -|----------------------------------------------------------------------------------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| -| [`intellij.type`](tools_gradle_intellij_plugin.md#intellij-extension-type) | `IU` for IntelliJ IDEA Ultimate. The Go plugin isn't compatible with IntelliJ IDEA Community Edition. | -| [`intellij.version`](tools_gradle_intellij_plugin.md#intellij-extension-version) | Set to the same `IU` BRANCH.BUILD as the GoLand target version, e.g. `193.5233.102`. | -| [`intellij.plugins`](tools_gradle_intellij_plugin.md#intellij-extension-plugins) |

    `org.jetbrains.plugins.go:193.5233.102.83` for the Go plugin.

    See below for Go plugin version information.

    | +| Gradle IntelliJ Plugin Attribute | Attribute Value | +|----------------------------------------------------------------------------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| [`intellij.type`](tools_gradle_intellij_plugin.md#intellij-extension-type) | `IU` for IntelliJ IDEA Ultimate. | +| [`intellij.version`](tools_gradle_intellij_plugin.md#intellij-extension-version) | Set to the same `IU` BRANCH.BUILD as the GoLand target version, e.g. `193.5233.102`. | +| [`intellij.plugins`](tools_gradle_intellij_plugin.md#intellij-extension-plugins) |

    `org.jetbrains.plugins.go:193.5233.102.83` for the Go plugin.

    See below for Go plugin version information.

    | | [`runIde.ideDir`](tools_gradle_intellij_plugin.md#tasks-runide-idedir) |

    Path to locally installed target version of GoLand. For example, on macOS:

    /Users/\$USERNAME\$/Library/Application Support/JetBrains/Toolbox/apps/Goland/ch-0/193.5233.112/GoLand.app/Contents.

    |
    diff --git a/topics/products/idea/idea.md b/topics/products/idea/idea.md index a04c55e4e07..9aac75a1393 100644 --- a/topics/products/idea/idea.md +++ b/topics/products/idea/idea.md @@ -8,11 +8,6 @@ -[IntelliJ IDEA](https://www.jetbrains.com/idea/) is available in two editions: IntelliJ Community Edition and IntelliJ IDEA Ultimate. - -See [Choose your edition](https://www.jetbrains.com/idea/features/#choose-your-edition) and [Feature Comparison](https://www.jetbrains.com/products/compare/?product=idea&product=idea-ce) for a detailed comparison. - - ## IntelliJ IDEA Plugin Setup {id="ideaPluginSetup"} @@ -22,7 +17,7 @@ See [Choose your edition](https://www.jetbrains.com/idea/features/#choose-your-e -Define a dependency using [`intellijIdeaCommunity()` or `intellijIdeaUltimate()`](tools_intellij_platform_gradle_plugin_dependencies_extension.md), see _Versions_ link on top of this page for all available versions. +Define a dependency using [`intellijIdea()`](tools_intellij_platform_gradle_plugin_dependencies_extension.md), see _Versions_ link on top of this page for all available versions. See [](tools_intellij_platform_gradle_plugin.md#dependenciesLocalPlatform) for using a local installation. Minimum build.gradle.kts setup: @@ -37,7 +32,7 @@ repositories { dependencies { intellijPlatform { - intellijIdeaCommunity("") + intellijIdea("") } } ``` @@ -47,10 +42,10 @@ dependencies { The configuration of IntelliJ IDEA plugin projects follows the methods described in [Configuring Plugin Projects using the IntelliJ IDEA Product Attribute](dev_alternate_products.md#using-the-intellij-idea-product-attribute). -| `gradle-intellij-plugin` Attribute | Attribute Value | -|----------------------------------------------------------------------------------|-----------------------------------------------------------------------------------------------| -| [`intellij.type`](tools_gradle_intellij_plugin.md#intellij-extension-type) |

    `IC` for IntelliJ IDEA Community Edition (default)

    `IU` for [](idea_ultimate.md)

    | -| [`intellij.version`](tools_gradle_intellij_plugin.md#intellij-extension-version) | IDE version, e.g. `2022.2` | +| `gradle-intellij-plugin` Attribute | Attribute Value | +|----------------------------------------------------------------------------------|--------------------------------------------| +| [`intellij.type`](tools_gradle_intellij_plugin.md#intellij-extension-type) | `IU` for [IntelliJ IDEA](idea_ultimate.md) | +| [`intellij.version`](tools_gradle_intellij_plugin.md#intellij-extension-version) | IDE version, e.g. `2022.2` |
    diff --git a/topics/products/idea/idea_ultimate.md b/topics/products/idea/idea_ultimate.md index e03942666ec..da6fa6050c0 100644 --- a/topics/products/idea/idea_ultimate.md +++ b/topics/products/idea/idea_ultimate.md @@ -11,7 +11,6 @@ IntelliJ IDEA Ultimate comes with a number of additional features and bundled plugins. - ## IntelliJ IDEA Ultimate Plugin Setup diff --git a/topics/products/phpstorm/phpstorm.md b/topics/products/phpstorm/phpstorm.md index 72f81d79455..d6edab140cc 100644 --- a/topics/products/phpstorm/phpstorm.md +++ b/topics/products/phpstorm/phpstorm.md @@ -76,7 +76,7 @@ Click on an entry in the table's *Attribute* column to go to the documentation a PhpStorm plugins targeting versions older than 2022.2 are developed using the Ultimate Edition of IntelliJ IDEA. -The IntelliJ IDEA Ultimate Edition (with the PHP plugin) must be used for developing PhpStorm plugins because the PHP plugin is incompatible with IntelliJ IDEA Community Edition. +The IntelliJ IDEA (with the PHP plugin) must be used for developing PhpStorm plugins because the PHP plugin is incompatible with IntelliJ IDEA open source builds. However, this IntelliJ IDEA Ultimate configuration runs the risk of accidentally using some APIs that are not available in PhpStorm. The recommended best practice is to use PhpStorm for testing. @@ -89,7 +89,7 @@ To see how these attributes appear in the Gradle build script for PhpStorm, see | `gradle-intellij-plugin` Attribute | Attribute Value | |----------------------------------------------------------------------------------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| -| [`intellij.type`](tools_gradle_intellij_plugin.md#intellij-extension-type) | `IU` for IntelliJ IDEA Ultimate. The required PHP plugin isn't compatible with IntelliJ IDEA Community Edition. | +| [`intellij.type`](tools_gradle_intellij_plugin.md#intellij-extension-type) | `IU` for IntelliJ IDEA. The required PHP plugin isn't compatible with IntelliJ IDEA open source builds. | | [`intellij.version`](tools_gradle_intellij_plugin.md#intellij-extension-version) | Set to the same `IU` BRANCH.BUILD as the PhpStorm target version, e.g. `193.5233.102`. | | [`intellij.plugins`](tools_gradle_intellij_plugin.md#intellij-extension-plugins) |

    `com.jetbrains.php:193.5233.102` for the PHP plugin.

    See below for PHP plugin version information.

    | | [`runIde.ideDir`](tools_gradle_intellij_plugin.md#tasks-runide-idedir) |

    Path to locally installed target version of PhpStorm. For example, on macOS:

    /Users/\$USERNAME\$/Library/Application Support/JetBrains/Toolbox/apps/PhpStorm/ch-0/193.5233.101/PhpStorm.app/Contents.

    | diff --git a/topics/products/pycharm/pycharm.md b/topics/products/pycharm/pycharm.md index 2c67633beaa..e3b33c95cf4 100644 --- a/topics/products/pycharm/pycharm.md +++ b/topics/products/pycharm/pycharm.md @@ -18,7 +18,7 @@ Plugin projects for PyCharm can be developed using [IntelliJ IDEA](idea.md). -Define a dependency using [`pycharmCommunity()` or `pycharmProfessional()`](tools_intellij_platform_gradle_plugin_dependencies_extension.md), see _Versions_ link on top of this page for all available versions. +Define a dependency using [`pycharm()`](tools_intellij_platform_gradle_plugin_dependencies_extension.md), see _Versions_ link on top of this page for all available versions. See [](tools_intellij_platform_gradle_plugin.md#dependenciesLocalPlatform) for using a local installation. A dependency on the matching bundled `PythonCore`/`Pythonid` plugin (see [](#python-plugins) below) must be added using the [`bundledPlugin()`](tools_intellij_platform_gradle_plugin_dependencies_extension.md#plugins) helper. @@ -35,7 +35,7 @@ repositories { dependencies { intellijPlatform { - pycharmCommunity("") + pycharm("") bundledPlugin("PythonCore") } } @@ -67,10 +67,10 @@ As described in [Configuring the plugin.xml File](dev_alternate_products.md#conf ### Python Plugins -| Plugin | Plugin ID | API | -|------------------------------------------------------------------------------------------------|--------------|-------------------------------------| -| [Python Community Edition](https://plugins.jetbrains.com/plugin/7322-python-community-edition) | `PythonCore` | PyCharm Community Edition (`PC`) | -| [Python](https://plugins.jetbrains.com/plugin/631-python) | `Pythonid` | PyCharm Professional Edition (`PY`) | +| Plugin | Plugin ID | API | +|------------------------------------------------------------------------------------------------|--------------|----------------------------------| +| [Python Community Edition](https://plugins.jetbrains.com/plugin/7322-python-community-edition) | `PythonCore` | PyCharm Community Edition (`PC`) | +| [Python](https://plugins.jetbrains.com/plugin/631-python) | `Pythonid` | PyCharm(`PY`) | #### Python Plugins 2024.2 @@ -82,7 +82,7 @@ When using functionality from `Pythonid`, a dependency on _both_ `PythonCore` an ## Available PyCharm APIs -See [](intellij_community_plugins_extension_point_list.md) for PyCharm Community. +See [](intellij_community_plugins_extension_point_list.md) for PyCharm. ## Additional Articles and Resources diff --git a/topics/products/rider/rider.md b/topics/products/rider/rider.md index 599874bc360..1d2bb87f678 100644 --- a/topics/products/rider/rider.md +++ b/topics/products/rider/rider.md @@ -60,6 +60,70 @@ And the following plugin.xml would require placing the file under <
    ``` +## Using Custom Icons from the Dotnet Rider Plugin Part + +Some feature integrations, like adding a new gutter mark or a new line marker, require passing an Icon from the Dotnet plugin part to the IntelliJ plugin part. + +A registration of an icon for such cases can be accomplished so: + +```c# +public static class MyIconIds +{ + // Note that the path string can _not_ start with a "/" here! + public static readonly IconId RiderIconId = + new FrontendIconId("icons/rider.svg"); +} +``` + +Then an icon should be turned into a model icon to be passed through the protocol with a call similar to the following: + +```c# +var modelIcon = Shell.Instance.GetComponent() + .Transform(frontendIconId); +``` + +The complete lifting routine in the IntelliJ plugin part for a model yielded by `IIconHost` can be achieved in the following way: + +```kotlin +// Get the first classloader from the list +// [RiderIconsCache::class.java.classLoader, ...pluginClassLoaders] +// that has the `path` in its resources +fun tryGetClassLoaderForPath(path: String): ClassLoader? { + /* ... */ +} + +fun liftIcon(model: FrontendIconModel): Icon { + return RiderIconCache.getInstance().getOrPut(model.path) { + val iconLoader = tryGetClassLoaderForPath(model.path) + if (iconLoader == null) { + return@getOrPut ReSharperIcons.Special.InvalidIcon + } + + val foundIcon = IconLoader.findIcon(model.path, iconLoader) + if (foundIcon == null) { + return@getOrPut ReSharperIcons.Special.InvalidIcon + } + } +} +``` + +If it is required for an implementation of a custom feature, the entry point for this conversion can be called so: + +```kotlin +val icon = service().createIcon(iconModel) +``` + +The example for such icon passing can be found in the [JetBrains Rider Plugin Template](https://github.com/ForNeVeR/rider-plugin-template). + +Please note that this way of setting up backend icon IDs for a plugin will work _only_ in Rider. +If the plugin is designed to work with _both_ ReSharper and Rider, add the icon as a _custom compiled icon_ +following the instructions in the [ReSharper DevGuide](https://www.jetbrains.com/help/resharper/sdk/Platform__Icons.html#custom-compiled-icons). + +To be loaded in the IntelliJ Platform, such icons are expected to be present under /resharper/$category/$iconName.svg in _some_ plugin resources directory, where: +- `$category` is the name of the generated `ThemedIcons` C# class without the `ThemedIcons` suffix +- `$iconName` is the name of the generated icon C# class +The classloader lookup routine is the same in this case as with the `FrontendIconModel`s. + ## Open Source Rider Plugins It can be useful to refer to existing projects to help understand how to build plugins for Rider. diff --git a/topics/products/rubymine/rubymine.md b/topics/products/rubymine/rubymine.md index 1ff260a98e6..c4decc073ca 100644 --- a/topics/products/rubymine/rubymine.md +++ b/topics/products/rubymine/rubymine.md @@ -58,7 +58,7 @@ To see how these attributes appear in a similar Gradle build script for PhpStorm | [`intellij.plugins`](tools_gradle_intellij_plugin.md#intellij-extension-plugins) |

    `org.jetbrains.plugins.ruby:2019.2.20191029` for the Ruby plugin.

    See below for Ruby plugin version information.

    | | [`runIde.ideDir`](tools_gradle_intellij_plugin.md#tasks-runide-idedir) |

    Path to locally installed target version of RubyMine. For example, on macOS:

    /Users/\$USERNAME\$/Library/Application Support/JetBrains/Toolbox/apps/RubyMine/ch-0/192.7142.37/RubyMine.app/Contents.

    | -The required `org.jetbrains.plugins.ruby` plugin isn't compatible with IntelliJ IDEA Community Edition but is compatible with IntelliJ IDEA Ultimate (`IU`) edition. +The required `org.jetbrains.plugins.ruby` plugin isn't compatible with IntelliJ IDEA open source builds but is compatible with IntelliJ IDEA (`IU`). Product compatibility is determined from the Ruby plugin [version page](https://plugins.jetbrains.com/plugin/1293-ruby/versions). The Ruby plugin isn't bundled with `IU`, so the Ruby plugin version must be explicitly declared to support the target RubyMine (and `IU`) BRANCH.BUILD version. The correct Ruby plugin version is also determined from the Ruby plugin version page. diff --git a/topics/reference_guide/accessibility.md b/topics/reference_guide/accessibility.md new file mode 100644 index 00000000000..f4fb28f5104 --- /dev/null +++ b/topics/reference_guide/accessibility.md @@ -0,0 +1,342 @@ + + +# Accessibility + +Making the UI accessible to more people. + +Accessibility means building user interfaces that everyone can use, regardless of their abilities. +It allows people with different needs, such as those who rely on assistive technologies or need keyboard-only navigation, to fully interact with the product. +Follow these guidelines, based on [industry standards](https://www.w3.org/TR/WCAG22/), to ensure the UI is accessible for all. + +## Keyboard accessibility + +All functionality must be operable by using only the keyboard. +People who have trouble using a mouse, including those who are blind, have low vision, or have motor disabilities, rely on keyboard navigation to effectively use the interface. + +### Focus basics + +The basic way to interact with the UI by using the keyboard is to switch focus between components with Tab and Shift+Tab. +For some components, such as lists, drop-down menus, or tables, arrow keys can also be used to navigate between items. +Once a component is focused, it can be activated by pressing Space. + +Make all interactive elements focusable to achieve [full keyboard operability](https://www.w3.org/WAI/WCAG22/Understanding/keyboard.html). +This includes buttons, checkboxes, text fields, lists, tables, dropdowns, and other controls that users can interact with. + +Non-interactive components, such as labels and panels, should not be focusable. +However, in some cases, they can be focusable to let screen reader users access important information. +Use [`ScreenReader.isActive()`](%gh-ic%/platform/util/ui/src/com/intellij/util/ui/accessibility/ScreenReader.java) to adjust the behavior only for screen reader users. + +### Keyboard traps + +Make the UI traversable in a cycle without trapping the keyboard focus. +A [keyboard focus trap](https://www.w3.org/WAI/WCAG22/Understanding/no-keyboard-trap.html) occurs when a user cannot navigate away from a component by using the standard keyboard navigation. +This prevents them from accessing other parts of the interface. + +Ensure that a user can always navigate away from any focusable component by using Tab, Shift+Tab, or Escape. +For instance, continuously pressing Tab or Shift+Tab in a dialog should result in cycling through all components and returning to the starting point. +To break out of such focus loops, use Escape to close dialogs and popups, or move focus back from a tool window to the editor. + +### Managing focus + +When new content appears, such as popups, modal dialogs, or dynamic content, ensure that: + +* Focus is moved to the new content, or there is a way to reach it by using only the keyboard. +* Focus is not moved unexpectedly when users are interacting with components like lists or dropdowns to avoid a [change of context](https://www.w3.org/WAI/WCAG22/Understanding/on-focus.html#dfn-changes-of-context). + +## Assistive technology support + +Assistive technologies, such as screen readers and voice control, rely on accessibility metadata provided by UI components. +For example, a checkbox might be announced by screen readers as "Don't ask again, checkbox, not checked, Alt+D". +Voice control users can say "Press Don't ask again" to activate the checkbox. +This integration is enabled by properly defined accessible metadata. + +Follow these guidelines to ensure that users of assistive technology can fully interact with the UI. + +### Accessible properties + +Each UI component has an associated [`javax.accessibility.AccessibleContext`](https://docs.oracle.com/en/java/javase/21/docs/api/java.desktop/javax/accessibility/AccessibleContext.html) object that defines properties for assistive technologies. +The accessible context can also implement [`Accessible*`](https://docs.oracle.com/en/java/javase/21/docs/api/java.desktop/javax/accessibility/package-summary.html#class-summary) interfaces to provide additional metadata or ways for assistive technologies to interact with the component. + +> For [common UI components](Components.topic), basic accessibility support is often already implemented. +> But when creating custom components or extending existing ones, you may need to extend the accessible context or modify its properties. +> +{style="note"} + +Example of customizing the accessible context and its properties: + + + +```kotlin +class ActionLink : JButton() { + override fun getAccessibleContext(): AccessibleContext { + if (accessibleContext == null) { + accessibleContext = object : AccessibleAbstractButton() { + override fun getAccessibleRole() = AccessibleRole.HYPERLINK + override fun getAccessibleValue() = null + } + } + return accessibleContext + } +} + +val link = ActionLink() +link.accessibleContext.accessibleName = "Open in browser" +``` + + + + +```java +class ActionLink extends JButton { + @Override + public AccessibleContext getAccessibleContext() { + if (accessibleContext == null) { + accessibleContext = new AccessibleAbstractButton() { + @Override + public AccessibleRole getAccessibleRole() { + return AccessibleRole.HYPERLINK; + } + + @Override + public AccessibleValue getAccessibleValue() { + return null; + } + }; + } + return accessibleContext; + } +} + +ActionLink link = new ActionLink(); +link.getAccessibleContext().setAccessibleName("Open in browser"); +``` + + + + +#### Accessible name and description + +An [accessible name](https://docs.oracle.com/en/java/javase/21/docs/api/java.desktop/javax/accessibility/AccessibleContext.html#getAccessibleName()) is the label that defines the component's purpose for assistive technology users. +Set a clear and descriptive accessible name for all focusable components. + +For example, a simple button with text should have that text as its accessible name. +For a text field with a label in front of it, the accessible name should be the label's text. +A list without a visible title should still have an accessible name that describes its content. + +In many cases, the accessible name is already taken implicitly from the following sources: + +* The text property of components such as labels or buttons. +* Tooltip text. +* The label of the component that was set by `JLabel.setLabelFor()`. + +If the name was not applied implicitly, set it by calling `AccessibleContext.setAccessibleName()` or by overriding `AccessibleContext.getAccessibleName()`: + + + + +```kotlin +class AccessibleCheckBox : AccessibleJLabel() { + override fun getAccessibleName() = myLabel.text +} + +checkBox.accessibleContext.accessibleName = "Don't ask again" +``` + + + + +```java +class AccessibleCheckBox extends AccessibleJLabel { + @Override + public String getAccessibleName() { + return myLabel.getText(); + } +} + +checkBox.getAccessibleContext().setAccessibleName("Don't ask again"); +``` + + + + +Tips for choosing an accessible name: + +* Don't include the component's role in the accessible name. + For example, for a password text field, set the name as "Password" instead of "Password text field." +* For complex components, include all visible information in the accessible name. + For example, for a panel that consists of a title, subtitle, and icon, combine all these parts in the accessible name. + +An accessible description provides additional context, such as instructions, keyboard shortcuts, placeholders, or explanatory text. +Use it for supplementary information that helps users understand how to interact with the component. + +The accessible description is set similarly to the accessible name, either by calling `AccessibleContext.setAccessibleDescription()` or by overriding `AccessibleContext.getAccessibleDescription()`. + +#### Accessible role + +The accessible role tells assistive technologies what type of component they are interacting with. +Use the [`AccessibleRole`](https://docs.oracle.com/en/java/javase/21/docs/api/java.desktop/javax/accessibility/AccessibleRole.html) value that correctly represents the component's function. + +The accessible role can be changed by overriding `AccessibleContext.getAccessibleRole()`: + + + + +```kotlin +class AccessibleCheckBox : AccessibleJLabel() { + override fun getAccessibleRole() = AccessibleRole.CHECK_BOX +} +``` + + + + +```java +class AccessibleCheckBox extends AccessibleJLabel { + @Override + public AccessibleRole getAccessibleRole() { + return AccessibleRole.CHECK_BOX; + } +} +``` + + + + +Tips for customizing the role: + +* Use `AccessibleRole.LABEL` for plain text content and `AccessibleRole.TEXT` for text fields and text areas that are editable or support selection. +* Set an appropriate button role: `AccessibleRole.PUSH_BUTTON`, `AccessibleRole.RADIO_BUTTON`, `AccessibleRole.TOGGLE_BUTTON`, or `AccessibleRole.HYPERLINK`. + +#### Accessible state + +The [accessible state](https://docs.oracle.com/en/java/javase/21/docs/api/java.desktop/javax/accessibility/AccessibleState.html) communicates the component's current condition to assistive technologies. +For example, it can tell screen reader users that the component is selected, expanded, or editable. + +Adjust the component's state set by overriding `AccessibleContext.getAccessibleStateSet()`: + + + + +```kotlin +class AccessibleCheckBox : AccessibleJLabel() { + override fun getAccessibleStateSet(): AccessibleStateSet { + val set = super.getAccessibleStateSet() + if (myChecked) { + set.add(AccessibleState.CHECKED) + } + return set + } +} +``` + + + + +```java +class AccessibleCheckBox extends AccessibleJLabel { + @Override + public AccessibleStateSet getAccessibleStateSet() { + AccessibleStateSet set = super.getAccessibleStateSet(); + if (myChecked) { + set.add(AccessibleState.CHECKED); + } + return set; + } +} +``` + + + + + +Notify assistive technologies when the state changes: + + + + +```kotlin +accessibleContext.firePropertyChange( + AccessibleContext.ACCESSIBLE_STATE_PROPERTY, + null, + AccessibleState.CHECKED +) +``` + + + + +```java +getAccessibleContext().firePropertyChange( + AccessibleContext.ACCESSIBLE_STATE_PROPERTY, + null, + AccessibleState.CHECKED +); +``` + + + + +#### Accessible interfaces + +Advanced accessibility features are provided through specialized interfaces, such as `AccessibleAction`, `AccessibleText`, `AccessibleSelection`, and `AccessibleValue`. +These are typically needed when implementing custom components from scratch. +Refer to the [list](https://docs.oracle.com/en/java/javase/21/docs/api/java.desktop/javax/accessibility/package-summary.html) of available interfaces to determine whether any need to be implemented. + +> Look at similar Swing components to see which interfaces they implement. For example, when working on a new slider-like component, check the interfaces implemented by [`JSlider.AccessibleJSlider`](https://docs.oracle.com/en/java/javase/21/docs/api/java.desktop/javax/swing/JSlider.AccessibleJSlider.html). +> +{style="note"} + +### Announcing live changes + +Screen readers announce accessible property changes of the currently focused component automatically. +For example, when a user checks a checkbox, the screen reader announces the new state. +This happens through property change events fired by the component. + +However, in some cases, users need to be notified of changes outside the focused component. Or the event that you want to notify about doesn't fit into existing property change support. + +For these scenarios, use [`AccessibleAnnouncerUtil.announce()`](%gh-ic%/platform/util/ui/src/com/intellij/util/ui/accessibility/AccessibleAnnouncerUtil.java) to make screen readers announce a specific string. + + + + +```kotlin +if (AccessibleAnnouncerUtil.isAnnouncingAvailable()) { + AccessibleAnnouncerUtil.announce(mySearchPanel, "No results found", true) +} +``` + + + + +```java +if (AccessibleAnnouncerUtil.isAnnouncingAvailable()) { + AccessibleAnnouncerUtil.announce(mySearchPanel, "No results found", true); +} +``` + + + + +Common cases for using announcements: + +* Error messages or validation results. +* Notifications or popups that are shown but don't receive keyboard focus. +* Background task completion. +* Search or filtering results. + +## Tools + +### Screen readers + +The IntelliJ Platform supports NVDA and JAWS screen readers on Windows, and VoiceOver on macOS. +Test the UI with a screen reader to verify that all functionality is available and that the announced information is correct and complete. + +> Learn more about screen reader functionality and commands from their official user guides: +> [NVDA](https://download.nvaccess.org/releases/2025.1.2/documentation/userGuide.html), +> [JAWS](https://support.freedomscientific.com/products/blindness/jawsdocumentation), +> and [VoiceOver](https://support.apple.com/guide/voiceover/welcome/mac). + +### UI Inspector + +Use the [UI Inspector](internal_ui_inspector.md) to examine accessible properties of UI components. +You can also perform an [accessibility audit](internal_ui_inspector.md#accessibility-checks) to check for common issues and get information on how to resolve them. diff --git a/topics/reference_guide/color_scheme_management.md b/topics/reference_guide/color_scheme_management.md index 52c5972dc80..5f341b071f7 100644 --- a/topics/reference_guide/color_scheme_management.md +++ b/topics/reference_guide/color_scheme_management.md @@ -16,7 +16,7 @@ if only standard attributes are set, they will not be used by the version before ### Text Attribute Key Dependency -The easiest and the best way to specify highlighting text attributes is to specify a dependency on one of standard keys defined in [`DefaultLanguageHighlighterColors`](%gh-ic%/platform/editor-ui-api/src/com/intellij/openapi/editor/DefaultLanguageHighlighterColors.java): +The easiest and the best way to specify highlighting text attributes is to specify a dependency on one of standard keys defined in [`DefaultLanguageHighlighterColors`](%gh-ic%/platform/core-api/src/com/intellij/openapi/editor/DefaultLanguageHighlighterColors.java): ```java static final TextAttributesKey MY_KEYWORD = diff --git a/topics/reference_guide/custom_language_support.md b/topics/reference_guide/custom_language_support.md index ce5251762ab..023ae5a5bd7 100644 --- a/topics/reference_guide/custom_language_support.md +++ b/topics/reference_guide/custom_language_support.md @@ -12,7 +12,7 @@ a plugin must implement only the language-specific part. ## Reference This part of the documentation explains the main concepts of the *Language API* and guides you through the sequence of steps that are usually required to develop a custom language plugin. -You can obtain additional information about the *Language API* from the Javadoc comments for the *Language API* classes and from the Properties language support source code, which is part of the [IntelliJ IDEA Community Edition](%gh-ic%/README.md) source code. +You can obtain additional information about the *Language API* from the Javadoc comments for the *Language API* classes and from the Properties language support source code, which is part of the [IntelliJ Platform](%gh-ic%/README.md) source code. ## Tutorial @@ -39,7 +39,7 @@ The webinar [How We Built Comma, the Raku IDE, on the IntelliJ Platform](https:/ * [](references_and_resolve.md) * [](symbols.md) * [](declarations_and_references.md) - * [](websymbols.md) + * [](polysymbols.md) * [](navigation.md) * [](code_completion.md) * {columns="2"} diff --git a/topics/reference_guide/custom_language_support/code_formatting.md b/topics/reference_guide/custom_language_support/code_formatting.md index 772a39dd3a7..fc109394b9a 100644 --- a/topics/reference_guide/custom_language_support/code_formatting.md +++ b/topics/reference_guide/custom_language_support/code_formatting.md @@ -175,7 +175,7 @@ This is useful for cases where nested alignments are needed, such as aligning a ### Examples - [Custom Language Support Tutorial: Formatter](formatter.md) -- [`JsonFormattingBuilderModel`](%gh-ic%/json/split/src/com/intellij/json/formatter/JsonFormattingBuilderModel.java) as an example that uses a `PsiBasedFormattingModel`. +- [`JsonFormattingBuilderModel`](%gh-ic%/json/src/com/intellij/json/formatter/JsonFormattingBuilderModel.java) as an example that uses a `PsiBasedFormattingModel`. - [`MarkdownFormattingModelBuilder`](%gh-ic%/plugins/markdown/core/src/org/intellij/plugins/markdown/lang/formatter/MarkdownFormattingModelBuilder.kt) as an example that uses a `DocumentBasedFormattingModel`. ### Further Tips @@ -206,7 +206,7 @@ To register a formatting pre-processor, a plugin has to provide an implementatio and register it in the . **Example:** -[`JsonTrailingCommaRemover`](%gh-ic%/json/split/src/com/intellij/json/formatter/JsonTrailingCommaRemover.java) removing trailing commas in JSON files +[`JsonTrailingCommaRemover`](%gh-ic%/json/src/com/intellij/json/formatter/JsonTrailingCommaRemover.java) removing trailing commas in JSON files ### Post-Processor diff --git a/topics/reference_guide/custom_language_support/implementing_lexer.md b/topics/reference_guide/custom_language_support/implementing_lexer.md index 5f0c6fd85a6..d1074610e85 100644 --- a/topics/reference_guide/custom_language_support/implementing_lexer.md +++ b/topics/reference_guide/custom_language_support/implementing_lexer.md @@ -41,7 +41,7 @@ Lexers used in other contexts can always return `0` from `getState()`. The easiest way to create a lexer for a custom language plugin is to use [JFlex](https://jflex.de). Classes [`FlexLexer`](%gh-ic%/platform/core-impl/src/com/intellij/lexer/FlexLexer.java) and [`FlexAdapter`](%gh-ic%/platform/core-impl/src/com/intellij/lexer/FlexAdapter.java) adapt JFlex lexers to the IntelliJ Platform Lexer API. -A [patched version of JFlex](https://github.com/JetBrains/intellij-deps-jflex) can be used with the lexer skeleton file [`idea-flex.skeleton`](%gh-ic%/tools/lexer/idea-flex.skeleton) located in the [IntelliJ IDEA Community Edition](https://github.com/JetBrains/intellij-community) source to create lexers compatible with `FlexAdapter`. +A [patched version of JFlex](https://github.com/JetBrains/intellij-deps-jflex) can be used with the lexer skeleton file [`idea-flex.skeleton`](%gh-ic%/tools/lexer/idea-flex.skeleton) located in the [IntelliJ Platform](https://github.com/JetBrains/intellij-community) source to create lexers compatible with `FlexAdapter`. The patched version of JFlex provides a new command-line option `--charat` that changes the JFlex generated code to work with the IntelliJ Platform skeleton. Enabling `--charat` option passes the source data for lexing as a `java.lang.CharSequence` and not as an array of characters. @@ -54,7 +54,7 @@ It provides syntax highlighting and other useful features for editing JFlex file {style="note"} **Examples:** -- [JFlex](%gh-ic%/plugins/properties/properties-psi-impl/src/com/intellij/lang/properties/parsing/Properties.flex) definition file for [Properties language plugin](%gh-ic%/plugins/properties) +- [JFlex](%gh-ic%/plugins/properties/properties-common/src/com/intellij/lang/properties/parsing/Properties.flex) definition file for [Properties language plugin](%gh-ic%/plugins/properties) - [Custom Language Support Tutorial: Lexer](lexer_and_parser_definition.md) ### Token Types diff --git a/topics/reference_guide/custom_language_support/implementing_parser_and_psi.md b/topics/reference_guide/custom_language_support/implementing_parser_and_psi.md index 8affbb0a0dc..c76d8ccc0a2 100644 --- a/topics/reference_guide/custom_language_support/implementing_parser_and_psi.md +++ b/topics/reference_guide/custom_language_support/implementing_parser_and_psi.md @@ -20,7 +20,7 @@ Nodes of the PSI tree are represented by classes implementing the [`PsiElement`] The top-level node of the PSI tree for a file needs to implement the [`PsiFile`](%gh-ic%/platform/core-api/src/com/intellij/psi/PsiFile.java) interface and is created in the [`ParserDefinition.createFile()`](%gh-ic%/platform/core-api/src/com/intellij/lang/ParserDefinition.java) method. **Example:** -[`ParserDefinition`](%gh-ic%/plugins/properties/properties-psi-impl/src/com/intellij/lang/properties/parsing/PropertiesParserDefinition.java) for [Properties language plugin](%gh-ic%/plugins/properties) +[`ParserDefinition`](%gh-ic%/plugins/properties/properties-common/src/com/intellij/lang/properties/parsing/PropertiesParserDefinition.java) for [Properties language plugin](%gh-ic%/plugins/properties) > To avoid unnecessary classloading when initializing the `ParserDefinition` extension point implementation, all `TokenSet` return values should use constants from a dedicated `$Language$TokenSets` class. > @@ -62,7 +62,7 @@ When the parser reaches the '+' token following 'b', it can call `precede()` to **Examples:** - [Custom Language Support Tutorial: Grammar and Parser](grammar_and_parser.md) (using Grammar-Kit) -- Simple [`PropertiesParser`](%gh-ic%/plugins/properties/properties-psi-impl/src/com/intellij/lang/properties/parsing/PropertiesParser.java) implementation for [Properties language plugin](%gh-ic%/plugins/properties/properties-psi-impl/src/com/intellij/lang/properties). +- Simple [`PropertiesParser`](%gh-ic%/plugins/properties/properties-common/src/com/intellij/lang/properties/parsing/PropertiesParserDefinition.java) implementation for [Properties language plugin](%gh-ic%/plugins/properties/properties-psi-impl/src/com/intellij/lang/properties). - Complex [`RegExpParser`](%gh-ic%/RegExpSupport/src/org/intellij/lang/regexp/RegExpParser.java) for RegEx language #### Whitespace and Comments diff --git a/topics/reference_guide/custom_language_support/language_server_protocol.md b/topics/reference_guide/custom_language_support/language_server_protocol.md index 6d3f6a6a930..8cd13fd64ce 100644 --- a/topics/reference_guide/custom_language_support/language_server_protocol.md +++ b/topics/reference_guide/custom_language_support/language_server_protocol.md @@ -27,11 +27,11 @@ Chris Simon shares the challenges faced and offers practical tips for aspiring L ## Supported IDEs The integration with the Language Server Protocol is created as an extension to the commercial IntelliJ-based IDEs. -Therefore, plugins using Language Server integration are not available in JetBrains products like -[IntelliJ IDEA](idea.md) Community Edition and [Android Studio](android_studio.md) from Google. +Therefore, plugins using Language Server integration are not available in +[IntelliJ IDEA](idea.md) open source builds and [Android Studio](android_studio.md) from Google. The LSP API is publicly available as part of the IntelliJ Platform in the following IDEs: -IntelliJ IDEA Ultimate, WebStorm, PhpStorm, PyCharm Professional, DataSpell, RubyMine, CLion, DataGrip, GoLand, Rider, and RustRover. +IntelliJ IDEA, WebStorm, PhpStorm, PyCharm, DataSpell, RubyMine, CLion, DataGrip, GoLand, Rider, and RustRover. Since 2025.1, it is also supported in unified [PyCharm without Pro subscription](https://blog.jetbrains.com/pycharm/2025/04/unified-pycharm/). @@ -95,6 +95,24 @@ and amend the values in gradle.properties accordingly. ### plugin.xml + + + + +The plugin.xml configuration file must specify the dependency on the LSP module: + +```xml + + + + com.intellij.modules.lsp + +``` + + + + + The plugin.xml configuration file must specify the dependency on the IntelliJ Platform _Ultimate_ module: ```xml @@ -105,6 +123,10 @@ The plugin.xml configuration file must specify the dependency on th ``` + + + + ### IDE Setup Since 2024.2, LSP API sources are provided with the `IntelliJ IDEA Ultimate sources` artifact. @@ -126,9 +148,25 @@ The LSP API sources are bundled in the IntelliJ IDEA Ultimate distribution and c The LSP support provided by the IntelliJ Platform covers the following features for these releases: +### 2025.3 + +- Server Initiated Progress ([`$/progress`](https://microsoft.github.io/language-server-protocol/specification/#progress)) +- Highlight Usages In File ([`textDocument/documentHighlight`](https://microsoft.github.io/language-server-protocol/specification/#textDocument_documentHighlight)) +- Go To Symbol ([`workspace/symbol`](https://microsoft.github.io/language-server-protocol/specification/#workspace_symbol)) +- File Structure / Structure ([`textDocument/documentSymbol`](https://microsoft.github.io/language-server-protocol/specification/#textDocument_documentSymbol)) +- Breadcrumbs ([`textDocument/documentSymbol`](https://microsoft.github.io/language-server-protocol/specification/#textDocument_documentSymbol)) +- Sticky Lines ([`textDocument/documentSymbol`](https://microsoft.github.io/language-server-protocol/specification/#textDocument_documentSymbol)) +- Parameter Info ([`textDocument/signatureHelp`](https://microsoft.github.io/language-server-protocol/specification/#textDocument_signatureHelp)) + +### 2025.2 + +- Inlay Hints ([`textDocument/inlayHint`](https://microsoft.github.io/language-server-protocol/specification/#textDocument_inlayHint)) [2025.2.2] +- Folding Range ([`textDocument/foldingRange`](https://microsoft.github.io/language-server-protocol/specification/#textDocument_foldingRange)) [2025.2.2] + ### 2025.1 - Document Link ([`textDocument/documentLink`](https://microsoft.github.io/language-server-protocol/specification/#textDocument_documentLink)) +- Pull Diagnostics ([`textDocument/diagnostic`](https://microsoft.github.io/language-server-protocol/specifications/#diagnostic)) (enabled by default in 2025.2) [2025.1.2] ### 2024.3 @@ -231,33 +269,42 @@ For more complex cases, the plugin may request to provide a detailed configurati ## Customization -To fine-tune or disable the implementation of LSP-based features, plugins may override the corresponding properties of the `LspServerDescriptor` class. -See the [property documentation](#ide-setup) for more details. +> To access LSP API source code and documentation see [](#ide-setup). +> +{style="note"} -### 2023.3 + -{id="customization_2023_3"} + -- `lspFormattingSupport` -- `lspHoverSupport` +To fine-tune or disable the implementation of LSP-based features, plugins may return a customized `LspCustomization` object from the `LspServerDescriptor.lspCustomization` property. +Available customization options are described by `LspCustomization`'s properties. -### 2023.2 +For example, see [`PrismaLspServerDescriptor`](%gh-ij-plugins%/prisma/src/org/intellij/prisma/ide/lsp/PrismaLspServerDescriptor.kt). + +The new API is backward-compatible. +Plugin LSP customizations implemented via deprecated `LspServerDescriptor`'s properties will work in 2025.2. +New LSP features will be customizable only via the new API. -{id="customization_2023_2"} + + + -- `lspGoToDefinitionSupport` -- `lspCompletionSupport` -- `lspDiagnosticsSupport` -- `lspCodeActionsSupport` -- `lspCommandsSupport` +To fine-tune or disable the implementation of LSP-based features, plugins may override the corresponding properties of the `LspServerDescriptor` class (see their documentation for details). -To handle custom (undocumented) requests and notifications from the LSP server, override `LspServerDescriptor.createLsp4jClient` property and the `Lsp4jClient` class according to their documentation. + + + + +> Note that LSP support is in active development and some customization options are available only in newer versions. +> +{style="warning"} + +To handle custom (undocumented) requests and notifications from the LSP server, override the `LspServerDescriptor.createLsp4jClient()` function and the `Lsp4jClient` class according to their documentation. To send custom (undocumented) requests and notifications to the LSP server, override `LspServerDescriptor.lsp4jServerClass` property and implement the `LspClientNotification` and/or `LspRequest` classes. The documentation in the source code includes implementation examples. -See the [bundled LSP API source code](#ide-setup) and its documentation for more information. - ## Troubleshooting All the IDE and LSP server communication logs are passed to the IDE log file. diff --git a/topics/reference_guide/custom_language_support/polysymbols.md b/topics/reference_guide/custom_language_support/polysymbols.md new file mode 100644 index 00000000000..f7c365e5487 --- /dev/null +++ b/topics/reference_guide/custom_language_support/polysymbols.md @@ -0,0 +1,88 @@ + + +# Poly Symbols + + + +Poly Symbols framework provides a layer over Symbol API, which facilitates Symbols sharing between various languages and technologies. + + +> This API is available starting from 2025.2 and is currently in development and thus in an experimental state. +> +{style="warning"} + +> In versions 2022.3 – 2025.1, this API was known as Web Symbols. +> +{style="note"} + +Poly Symbols is a framework built on top of the platform's [Symbol API](symbols.md). +It provides a generic layer, which allows sharing of Symbols between different languages and technologies. + +It reduces work needed to implement a new language or framework support with [Symbol API](symbols.md). +In many cases, only declarations, references, and code completion providers need to be implemented on the platform side and symbol contributors on the Poly Symbol framework side. +After that most of the aspects of support based on reference resolution, like find usages, documentation, or rename refactoring, will work out-of-the-box. + +## Poly Symbol Query Executor + +The main part of the framework is [`PolySymbolQueryExecutor`](%gh-ic%/platform/polySymbols/src/com/intellij/polySymbols/query/PolySymbolQueryExecutor.kt), +which supports three simple queries: +- list symbols +- get code completions +- match symbols with a name + +It uses symbols from scopes provided through [`PolySymbolQueryScopeContributor`](%gh-ic%/platform/polySymbols/src/com/intellij/polySymbols/query/PolySymbolQueryScopeContributor.kt). + +The list of scopes is built similarly to how code completion works. +Various contributors define patterns for `PsiElement`s for which they provide symbol scopes. +For each instance of `PolySymbolQueryExecutor`, the list of scopes is built anew depending on the provided PSI location. + +During query execution, the executor gets symbols or completion items from each scope on the list to build the query results. +The results of the queries may be customized by [`PolySymbolQueryResultsCustomizer`](%gh-ic%/platform/polySymbols/src/com/intellij/polySymbols/query/PolySymbolQueryResultsCustomizer.kt) allowing for a very robust way to filter or alter the results of any query. + +The `PolySymbolQueryExecutor` can be used in many places to provide symbols, but the main consumers of the API are reference and code completion providers. +The `PolySymbolQueryExecutor` simplifies reference and code completion providers by delegating the actual symbol resolution to [`PolySymbolScope`](%gh-ic%/platform/polySymbols/src/com/intellij/polySymbols/query/PolySymbolScope.kt). +The executor provides a customization layer as well and abstracts language integration from symbol sources allowing for symbols to be provided from various sources (e.g. source code, library code, or static symbol definitions, like Web Types). + +## Symbol Patterns + +`PolySymbolQueryExecutor`'s main advantage is the ability to evaluate symbol patterns. + +Many frameworks or libraries have custom syntaxes as a meta-language over regular language syntax. +Examples for this are various web frameworks (e.g. HTML attribute name microsyntax - see [Model Queries example](polysymbols_implementation.md#model-queries-example) for Vue directive syntax), but also message bundle keys, or plugin extension points defined in XML. +Using symbol patterns, it is relatively easy to define that micro syntax. +The pattern evaluator based on that information is able to recognize symbols making up a name of another symbol. + +With none or minimal customizations required, for such symbols, the Poly Symbols framework provides: +- code completion +- reference resolution +- documentation +- navigation +- semantic highlighting +- occurrences highlighting +- find usages +- rename refactoring + +This is possible because neither reference nor completion providers use `PolySymbolScope`s directly, but instead they depend on the query results from the `PolySymbolQueryExecutor`. +The executor can return a composite symbol for a reference provider, which then is split into name segments, and each of the recognized symbols has its own reference range. + +For a code completion provider, on the other hand, it can provide a set of completion items, which are results of evaluating all possible symbol names for the given patterns. +Pattern evaluator supports also multistaged completion, so it's possible to first complete a name prefix and then continue with completion of the rest of the pattern. + +## Summary + +Overall, the Poly Symbols framework can serve as a base for a language support, or can work on a meta-level, +to support frameworks or libraries, which are giving additional meaning to the existing language features. + +Currently, IDEs provide built-in integration for the following language features (see [](polysymbols_integration.md)): +- HTML: elements, attributes, and attribute values +- CSS: properties, custom properties, functions, classes, pseudo-elements, pseudo-classes, and parts +- JavaScript: string-literals, object properties, object literals, and symbols (in JavaScript and TypeScript) + +The following sections provide information on how to implement Poly Symbols for plugins and how to +define them statically through JSON schemas: +- [](polysymbols_implementation.md) +- [](polysymbols_web_types.md) + +## PolyContext + +Poly Symbols framework provides a convenient way to manage enablement of features through [`PolyContext` API](polysymbols_context.md). diff --git a/topics/reference_guide/custom_language_support/websymbols_context.md b/topics/reference_guide/custom_language_support/polysymbols_context.md similarity index 81% rename from topics/reference_guide/custom_language_support/websymbols_context.md rename to topics/reference_guide/custom_language_support/polysymbols_context.md index 85e373fb678..f7a7a039457 100644 --- a/topics/reference_guide/custom_language_support/websymbols_context.md +++ b/topics/reference_guide/custom_language_support/polysymbols_context.md @@ -1,24 +1,24 @@ -# Web Symbols Context - +# Poly Symbols Context + -How to use Web Symbols context detection to manage enablement of plugin features. +How to use Poly Symbols context detection to manage enablement of plugin features. One of the important qualities of well-written plugins is the enablement of its features only when needed. For instance, if a user does not have a particular web framework in their project, HTML files should not contain that framework-specific assistance. -Web Symbols framework provides various ways to detect current context -and retrieve it through `WebSymbolsContext.get(kind, ...)` methods. +Poly Symbols framework provides various ways to detect current context +and retrieve it through `PolyContext.get(kind, ...)` methods. -For a particular `kind` of Web Symbol context, there is only one `name` detected, and it can be `null` if +For a particular `kind` of Poly Symbol context, there is only one `name` detected, and it can be `null` if the context `kind` is not present in the location. ## Location - `PsiElement` vs `VirtualFile` The location can either be a `PsiElement`, or a `VirtualFile` with a `Project`. If the location is `PsiElement`, -the PSI tree of the containing file might be checked by `WebSymbolsContextProvider`, for instance, for some imports. +the PSI tree of the containing file might be checked by `PolyContextProvider`, for instance, for some imports. If the location is a `VirtualFile`, the PSI tree will not be acquired, so the resulting context may differ from the one acquired on a `PsiElement` location. This is expected. The `VirtualFile` location is used to, amongst others, determine a language to parse the file, so it cannot use a PSI tree. It must also be fast, @@ -29,21 +29,21 @@ at which context is checked. It is important, though, to remember that the langu be substituted if a context is detected on `VirtualFile` level. A good example of how context detection can be used is web frameworks, since at a particular location only -one of the frameworks can be used. Various `WebSymbolsContextProvider` extensions and context rules are used +one of the frameworks can be used. Various `PolyContextProvider` extensions and context rules are used to determine which of the frameworks (Vue, Angular, React, Astro, etc.) to enable at the particular location. -And each of the plugins calls `WebSymbolsContext.get("framework", ...)` to check if it's their framework, +And each of the plugins calls `PolyContext.get("framework", ...)` to check if it's their framework, which is enabled. -## `WebSymbolsContextProvider` +## `PolyContextProvider` -The most straightforward way to contribute context is to register a [`WebSymbolsContextProvider`](%gh-ic%/platform/webSymbols/src/com/intellij/webSymbols/context/WebSymbolsContextProvider.kt) -through and override one of `isEnabled()` methods +The most straightforward way to contribute context is to register a [`PolyContextProvider`](%gh-ic%/platform/polySymbols/src/com/intellij/polySymbols/context/PolyContextProvider.kt) +through and override one of `isEnabled()` methods to detect a context of a particular name and kind, e.g.: ```xml - @@ -51,10 +51,10 @@ to detect a context of a particular name and kind, e.g.: ``` The `StimulusContextProvider` can, for instance, check for JavaScript imports in the file to see if some additional Stimulus support -should be present in the file. The result should be cached, as `WebSymbolsContextProvider` methods are called very often. +should be present in the file. The result should be cached, as `PolyContextProvider` methods are called very often. ```kotlin -class StimulusContextProvider : WebSymbolsContextProvider { +class StimulusContextProvider : PolyContextProvider { override fun isEnabled(file: PsiFile): Boolean { if (file is HtmlCompatibleFile) { return CachedValuesManager.getCachedValue(file) { @@ -69,16 +69,16 @@ class StimulusContextProvider : WebSymbolsContextProvider { The presence of the context can be checked as follows: ```kotlin -WebSymbolsContext.get("stimulus-context", psiElement) == "true" +PolyContext.get("stimulus-context", psiElement) == "true" ``` -`WebSymbolsContextProvider` can also prevent a context from being detected. In this case, the `isForbidden` method should be overridden. +`PolyContextProvider` can also prevent a context from being detected. In this case, the `isForbidden` method should be overridden. To prevent any context of a particular kind, use `any` as a name, e.g.: ```xml - @@ -90,13 +90,13 @@ location and forbid the `framework` context to disable web frameworks support, l ## Context Rules -`WebSymbolsContextProvider` is straightforward to use, but it is not very efficient. When many providers look for similar information, +`PolyContextProvider` is straightforward to use, but it is not very efficient. When many providers look for similar information, a lot of calculations are repeated, affecting the overall performance of the IDE. One of the examples is when providers look for the presence of some package manager dependency (Node package, Ruby Gem, Maven or Gradle dependency, etc.). To optimize this lookup, context rules can be provided. ### Web Types with Context Rules -One of the ways to provide context rules is through a [Web Types](websymbols_web_types.md) file. +One of the ways to provide context rules is through a [Web Types](polysymbols_web_types.md) file. A top-level property `context-config` should be specified, e.g.: ```json @@ -202,7 +202,7 @@ Web Types can be embedded with a plugin by pointing to the file via extension po ```xml - @@ -221,12 +221,12 @@ choose the minimal version, for which the Web Types should be loaded. If context rules should always be loaded, then any name (preferably not used by any dependency) should be used for the dependency and the `enableByDefault` attribute set to `true`. -### `WebSymbolsContextRulesProvider` +### `PolyContextRulesProvider` -Context rules can also be provided dynamically through [`WebSymbolsContextRulesProvider`](%gh-ic%/platform/webSymbols/src/com/intellij/webSymbols/context/WebSymbolsContextRulesProvider.kt). +Context rules can also be provided dynamically through [`PolyContextRulesProvider`](%gh-ic%/platform/polySymbols/src/com/intellij/polySymbols/context/PolyContextRulesProvider.kt). -To do that, register a [`WebSymbolsQueryConfigurator`](%gh-ic%/platform/webSymbols/src/com/intellij/webSymbols/query/WebSymbolsQueryConfigurator.kt) -through and implement `getContextRulesProviders()`. +To do that, register a [`PolySymbolQueryConfigurator`](%gh-ic%/platform/polySymbols/src/com/intellij/polySymbols/query/PolySymbolQueryConfigurator.kt) +through and implement `getContextRulesProviders()`. It is important that the results are stable, because any unexpected change in the rules will cause rescanning of the project, dropping of all caches and restarting code analysis. @@ -266,16 +266,16 @@ When choosing between different patterns matching the same file name, the follow 2. Choose a pattern which has a file name pattern (i.e., doesn't end with `**` or `/`). 3. Choose a pattern that was defined first. -## `WebSymbolsContextSourceProximityProvider` +## `PolyContextSourceProximityProvider` -`WebSymbolsContextSourceProximityProvider` allows providing evaluation logic for the context rules. It should be used when +[`PolyContextSourceProximityProvider`](%gh-ic%/platform/polySymbols/src/com/intellij/polySymbols/context/PolyContextSourceProximityProvider.kt) allows providing evaluation logic for the context rules. It should be used when working on integrating support for a package manager or a language which has a way to define global libraries. The provider should be registered -through . +through . The provider has a single method to be overridden — `calculateProximity()`. When `sourceKind` parameter matches the provider requirements, it should calculate the [proximity](#context-proximity) of each source provided by `sourceNames`. For instance, when supporting a package manager and the method is called with `sourceKind` being a `PackageManagerDependency` with the appropriate name, the provider should calculate the [proximity](#context-proximity) of each dependency provided through `sourceNames` parameter. The `Result` object contains also a `modificationTrackers` set field, which is used to track when the cached results should be recalculated. It is crucial to have as few trackers as possible and refresh the cache as seldom as possible -because the results are used in every call to the `WebSymbolContext.get()` method. +because the results are used in every call to the `PolyContext.get()` method. diff --git a/topics/reference_guide/custom_language_support/polysymbols_implementation.md b/topics/reference_guide/custom_language_support/polysymbols_implementation.md new file mode 100644 index 00000000000..02fa5968d5f --- /dev/null +++ b/topics/reference_guide/custom_language_support/polysymbols_implementation.md @@ -0,0 +1,385 @@ + + +# Implementing Poly Symbols + + +Implementation details for the Poly Symbols API. + +The core element of the framework is a [`PolySymbol`](%gh-ic%/platform/polySymbols/src/com/intellij/polySymbols/PolySymbol.kt). +It is identified through `name` and `qualifiedKind` properties. +The symbol has a very generic meaning and may represent a variable in some language, or an endpoint of some web server, or a file. + +The symbol lifecycle is limited to a single read action. +To ensure its survival between read actions, use `PolySymbol.createPointer()` to create a symbol pointer. +Provided the symbol remains valid, dereferencing the pointer will return a new instance of the symbol. +It should be noted that during a write action, the symbol might not survive a PSI tree commit. +Therefore, creating a pointer prior to the commit and dereferencing it post-commit is advised. + +Symbols, which share some common characteristics, should be grouped using the same `qualifiedKind`. +The `qualifiedKind` consists of a `namespace`, which roughly indicates a language or a framework the symbol belongs to, and a `kind`, which roughly indicates what the symbol's basic characteristics are. + +Examples: +- a CSS property: `namespace: CSS`, `kind: properties` +- a Java class: `namespace: Java`, `kind: classes` +- a plugin extension: `namespace: ij-plugin`, `kind: extensions` + +A Poly Symbol can originate from source code analysis, or it can be a symbol statically defined through [Web Types](polysymbols_web_types.md) (JSON) or some other custom format. +In both cases, such a symbol can have some `source` defined. +Each symbol is treated by the framework the same, regardless of their origin. + +Consumers of symbols should avoid casting the `PolySymbol` to some other specialized interface, as it prevents third party symbol providers from customizing symbols or providing additional symbols. + +## General Properties + +`PolySymbol` has a number of properties which are used across IDE features: + +{style="full"} +`qualifiedKind` +: Describes which group of symbols (kind) within the particular language +or concept (namespace) the symbol belongs to. + +`name` +: The name of the symbol. If the symbol does not have a pattern, the name will be used as-is for matching. + +`origin` +: Specifies where this symbol comes from. +Besides descriptive information like framework, library, version, or default icon, it also provides an interface to load symbol types and icons. + +`icon` +: An optional icon associated with the symbol, which is going to be used across the IDE. +If none is specified, a default icon of the `origin` will be used and if that’s not available, a default icon for symbol `namespace` and `kind`. + +`priority` +: Symbols with higher priority will have precedence over those with lower priority when matching is performed. +Symbols with higher priority will also show higher on the completion list. + +`apiStatus` +: Documents API status of the symbol. It is one of the sub-interfaces of [`PolySymbolApiStatus`](%gh-ic%/platform/polySymbols/src/com/intellij/polySymbols/PolySymbolApiStatus.kt): +`Stable`, `Experimental` or `Deprecated`. +Deprecated symbols are appropriately highlighted in the code editor, code completion, and quick documentation. + +`modifiers` +: A set of symbol modifiers. +The framework contains constants for many modifiers known from various programming languages. +However, implementations are free to define other modifiers using `PolySymbolModifier.get`. + +: When a match is performed over a sequence of symbols, use `PolySymbolMatchCustomizer` to customize +how modifiers from different symbols in the sequence are merged for the resulting `PolySymbolMatch` modifiers. + +`psiContext` +: A `PsiElement`, which is a file or an element, which can be used to roughly locate the source of the symbol within a project to provide a context for loading additional information, like types. +If the symbol is +[`PsiSourcedPolySymbol`](%gh-ic%/platform/polySymbols/src/com/intellij/polySymbols/search/PsiSourcedPolySymbol.kt) +(see [](#psisourcedpolysymbol)), then `psiContext` is equal to `source`. + +`presentation` +: Returns +[`TargetPresentation`](%gh-ic%/platform/core-api/src/com/intellij/platform/backend/presentation/TargetPresentation.kt) +used by +[`SearchTarget`](%gh-ic%/platform/lang-impl/src/com/intellij/find/usages/api/SearchTarget.kt) +and +[`RenameTarget`](%gh-ic%/platform/lang-impl/src/com/intellij/refactoring/rename/api/RenameTarget.kt). +Default implementations of +[`PolySymbolRenameTarget`](%gh-ic%/platform/polySymbols/src/com/intellij/polySymbols/refactoring/PolySymbolRenameTarget.kt) +and +[`PolySymbolSearchTarget`](%gh-ic%/platform/polySymbols/src/com/intellij/polySymbols/search/PolySymbolSearchTarget.kt) +use the `presentation` property. + +`searchTarget` +: Implement to provide usage search for the symbol. +In most cases the implementation would simply call `PolySymbolSearchTarget.create`. + +: Symbol can also implement the `SearchTarget` interface directly and override its methods, in which case `PolySymbolSearchTarget` returned by `searchTarget` property is ignored. +If the returned target is not a `PolySymbolSearchTarget`, a dedicated `UsageSearcher` needs to be implemented to handle it. + +`searchTarget` +: Implement to provide rename refactoring for the symbol. +In most cases the implementation would simply call `PolySymbolRenameTarget.create`. + +: Symbol can also implement the `RenameTarget` interface directly and override its methods, in which case `PolySymbolRenameTarget` returned by `renameTarget` property is ignored. +If the returned target is not a `PolySymbolRenameTarget`, a dedicated `RenameUsageSearcher` needs to be implemented to handle it. + +## Query Related Properties + +The following properties are related to name matching and code completion queries: + +`queryScope` +: When a pattern is being evaluated, matched symbols can provide additional scope for further resolution in the pattern. +By default, the `queryScope` returns the symbol itself if it implements the ` PolySymbolScope ` interface. + +`extension` +: Specifies whether the symbol is an extension. +When matched along with a non-extension symbol, it can provide or override some properties of the symbol, or it can extend its scope contents. + +## Methods +{#query-methods} + +{style="full"} +`get(property: PolySymbolProperty)` +: Accessor for various symbol properties. Plugins can use properties to provide additional information on the symbol. +All properties supported by IDEs are defined through `PROP_*` constants of the `PolySymbol` interface. +Check their documentation for further reference. To ensure that results are properly cast, use the +`PolySymbolProperty.tryCast` method for returned values. + +`getDocumentationTarget(location: PsiElement?)` +: Used by the Poly Symbols framework to get a [`DocumentationTarget`](%gh-ic%/platform/lang-impl/src/com/intellij/platform/backend/documentation/DocumentationTarget.kt), which handles documentation rendering for the symbol. +The additional ` location ` parameter allows calculating more specific properties for the symbol documentation, like inferred generic parameters. + +: By default, `PolySymbolDocumentationTarget.create` method should be used to build the documentation target for the symbol. +It allows for documentation to be further customized by [`PolySymbolDocumentationCustomizer`](%gh-ic%/platform/polySymbols/src/com/intellij/polySymbols/documentation/PolySymbolDocumentationCustomizer.kt)s. + +`getNavigationTargets(project: Project)` +: Override to provide navigation targets for the symbol. +The `SymbolNavigationService` may be used to create navigation targets. + +`isEquivalentTo(symbol: Symbol)` +: Returns true if two symbols are the same or equivalent for resolve purposes. + +`matchContext(context: PolyContext)` +: Allows filtering out symbol from query results if the context is not matched. +By default, only the current symbol framework from the `origin` property is checked. + +`createPointer()` +: Returns the pointer to the symbol, which can survive between read actions. +The dereferenced symbol should be valid, for example, any PSI-based properties should return valid `PsiElement`s. + +`getModificationCount()` +: Symbols can be used in +[`CachedValue`](%gh-ic%/platform/core-api/src/com/intellij/psi/util/CachedValue.java)s +as dependencies. +If a symbol instance can mutate over time, it should properly implement this method. + +## `PsiSourcedPolySymbol` + +A symbol should implement +[`PsiSourcedPolySymbol`](%gh-ic%/platform/polySymbols/src/com/intellij/polySymbols/search/PsiSourcedPolySymbol.kt) +if its declaration is a regular `PsiElement`, for example, a variable or a declared type. +Once a symbol implements this interface, it can be searched and refactored together with the PSI element declaration. +In case a symbol is: +- a part of `PsiElement` (for instance, being part of a string literal) +- spans multiple PSI elements +- does not correlate one-to-one with a PSI element + +contribution of a dedicated declaration provider instead of implementing this interface is recommended. + +### Properties +{#psisourcedpolysymbol-properties} + +{style="full"} +`source` +: The `PsiElement`, which is the symbol declaration. + +## `PolySymbolWithPattern` + +The [`PolySymbolWithPattern`](%gh-ic%/platform/polySymbols/src/com/intellij/polySymbols/query/PolySymbolWithPattern.kt) represents a symbol, which might consist of other symbols and provides a pattern, +which describes the relationship. + +### Properties +{#polysymbolwithpattern-properties} + +{style="full"} +`pattern` +: The pattern to match names against. +As a result of pattern matching, a [`PolySymbolMatch`](%gh-ic%/platform/polySymbols/src/com/intellij/polySymbols/query/PolySymbolMatch.kt) will be created. +A pattern may specify that a reference to other Poly Symbols is expected in some part of it. +For such places, appropriate segments with referenced Poly Symbols will be created, and navigation, validation, and refactoring support are available out-of-the-box. + +## `CompositePolySymbol` + +[`PolySymbolMatch`](%gh-ic%/platform/polySymbols/src/com/intellij/polySymbols/query/PolySymbolMatch.kt) +and some special symbols can have a name, which consists of other Poly Symbols. + +### Properties +{#compositepolysymbol-properties} + +{style="full"} +`nameSegments` +: List of +[`PolySymbolNameSegment`](%gh-ic%/platform/polySymbols/src/com/intellij/polySymbols/PolySymbolNameSegment.kt). +Each segment describes a range in the symbol name. +Segments can be built of other Poly Symbols and/or have related matching problems - missing the required part, unknown symbol name or be a duplicate of another segment. +See the [Model Queries Example](#model-queries-example) section for an example. + +## `PolySymbolScope` + +Each `PolySymbol` can contain other Poly Symbols, in which case it should implement `PolySymbolScope`. +For instance, an HTML element symbol would contain some HTML attribute symbols, or a JavaScript class symbol would contain field and method symbols. + +When configuring queries, `PolySymbolScope`s contributed by [`PolySymbolQueryScopeContributor`](%gh-ic%/platform/polySymbols/src/com/intellij/polySymbols/query/PolySymbolQueryScopeContributor.kt) for the given location are added to a `PolySymbolQueryStack`] to create an initial scope for symbol resolve. +During pattern matching with symbol sequences, all matched symbols' query scopes (`PolySymbol.queryScope`) are added to the stack allowing for extending scope matching. + +### Methods +{#polysymbolscope-methods} + +{style="full"} +`getSymbols()` +: Returns symbols within the scope. +If the provided `name` is `null`, no pattern evaluation will happen, and all symbols of a particular kind and from a particular namespace will be returned. + +`getCodeCompletions()` +: Returns code completions for symbols within the scope. + +`isExclusiveFor()` +: When scope is exclusive for a particular namespace and kind, resolve will not continue down the stack during pattern matching. + +`createPointer()` +: Returns the pointer to the symbol scope, which can survive between read actions. +The dereferenced symbol scope should be valid. + +`getModificationCount()` +: Symbol scopes are used in CachedValues as dependencies for query executors. +If a symbol scope instance can mutate over time, it should properly implement this method. + +When implementing a scope containing many elements, an extension of +[`PolySymbolScopeWithCache`](%gh-ic%/platform/polySymbols/src/com/intellij/polySymbols/utils/PolySymbolScopeWithCache.kt) is advised. +This structure caches the list of symbols and uses an efficient cache mechanism to speed up queries. +On extension of this class, it's only necessary to override `initialize()` and provide parameters to the super constructor to specify the caching strategy for the results. + +## Model Queries + +Poly Symbols can contain patterns, which allow composing them from other Poly Symbols. +Such symbols should implement the [`PolySymbolWithPattern`](%gh-ic%/platform/polySymbols/src/com/intellij/polySymbols/query/PolySymbolWithPattern.kt) interface. + +To find which symbols match available patterns, we need to make a match query. +One can also run a code completion query, which will produce a list of valid completions in the provided context, +or a symbol list query, which will list all available symbols. + +To perform a query, create a +[`PolySymbolQueryExecutor`](%gh-ic%/platform/polySymbols/src/com/intellij/polySymbols/query/PolySymbolQueryExecutor.kt) +using +[`PolySymbolQueryExecutorFactory`](%gh-ic%/platform/polySymbols/src/com/intellij/polySymbols/query/PolySymbolQueryExecutorFactory.kt). +The query executor will be configured by all registered +[`PolySymbolQueryScopeContributor`](%gh-ic%/platform/polySymbols/src/com/intellij/polySymbols/query/PolySymbolQueryScopeContributor.kt) +and +[`PolySymbolQueryConfigurator`](%gh-ic%/platform/polySymbols/src/com/intellij/polySymbols/query/PolySymbolQueryConfigurator.kt) +extensions based on the provided PSI context. +Scope contributors will provide initial Poly Symbol scopes, and configurators will provider rules for calculating Poly Symbols context, and rules for symbol names conversion. + +The result of the match query is a list of `PolySymbol`s. +Some of them might be +[`PolySymbolMatch`](%gh-ic%/platform/polySymbols/src/com/intellij/polySymbols/query/PolySymbolMatch.kt)es. +Such objects represent complex matches when patterns are used. +Poly Symbol Match has `nameSegments` property, which precisely describes how segments of the name relate to referenced Poly Symbols and whether there are any problems with resolution or the name itself. + +When working with code completion, one can query for the list of code completions. +To properly calculate completions, a position in the current text under completion is required. +As a result, a list of +[`PolySymbolCodeCompletionItem`](%gh-ic%/platform/polySymbols/src/com/intellij/polySymbols/completion/PolySymbolCodeCompletionItem.kt) +will be provided. + +### Example +{#model-queries-example} + +Let's consider a Vue directive. + +It is a special HTML attribute processed by the Vue framework at runtime or during compilation, which results in additional code being attached to the DOM element. +Its structure looks as follows: + +![JavaScript Example Image](polysymbols_web_types.svg){ width="706"} + +An example of how a Vue directive might be declared in Web Types is here. +Once a match query is run on `v-on:click.once.alt`, we will get a +[`PolySymbolMatch`](%gh-ic%/platform/polySymbols/src/com/intellij/polySymbols/query/PolySymbolMatch.kt) +with the following segments: + +1. `v-`: Vue directive pattern symbol +2. `on`: Vue `on` directive +3. `:` +4. `click`: DOM `click` event symbol +5. `.` +6. `once`: Vue `on` directive `once` modifier +7. `alt`: Vue `on` directive `alt` modifier + +### Patterns + +Usually one would create such elements using Web Types, but sometimes there might be a need to do that programmatically. + +To simplify resolution and make it less ambiguous, a segment to match is selected by taking everything up to static prefixes of the following patterns. +Thus, if we want to have symbol references and regular expressions in the pattern, they either have to terminate the pattern or must be followed by a static text. +A regular pattern static prefix is also considered a static text. + +There are seven types of patterns: + +1. String match: try to match an exact text, the match is case-sensitive. +2. Regular expression match: try to match a regular expression, the match can be case-insensitive. +3. Symbol reference placeholder: a symbol reference resolve will be attempted when this pattern is reached. + A resolve will be made by the symbols provider from an enclosing complex pattern. + If none of the symbols match the segment, the segment will have a [`MatchProblem.UNKNOWN_SYMBOL`](%gh-ic%/platform/polySymbols/src/com/intellij/polySymbols/PolySymbolNameSegment.kt) problem reported. + The matched symbol might be a [`PolySymbolMatch`](%gh-ic%/platform/polySymbols/src/com/intellij/polySymbols/query/PolySymbolMatch.kt) itself, which allows for nesting patterns. +4. Pattern sequence: a sequence of patterns. If some patterns are not matched, an empty segment with `MatchProblem.MISSING_REQUIRED_PART` will be created. +5. Complex pattern: this pattern is called complex because it makes several things: + - The provided patterns are treated as alternatives. + - It can have symbols resolver, which is used by nested symbol reference placeholder patterns. + - It allows adding an extra scope to resolve stack. + - A complex pattern might be optional, in which case its absence is not reported as an error in an enclosing sequence or complex pattern. + - The match can be repeated, and any duplicate segments might have a `MatchProblem.DUPLICATED` problem set. + - It can override proximity and priority, which by default is based on priority and proximity of matched symbols. + + {style="alpha-lower"} +6. Completion auto popup: a special pattern, which works only in code completion queries. + It delimits the place where when creating code completion items, pattern evaluation should be stopped and `...` added. + Selecting such items will result in adding the prefix part, and then another code completion popup will open. + The pattern can be sticky, which means that the prefix will be shown in the nested code completion list. +7. Single symbol reference (*since 2023.2*): try to match text against the symbol name, but put a reference to another element. + +### Query Context + +When performing queries, some symbols should be excluded and others included in particular contexts. +For instance, if we have an Angular project, none of the Vue components should be available. +[`PolyContext`](%gh-ic%/platform/polySymbols/src/com/intellij/polySymbols/context/PolyContext.kt) +is created using rules provided by [`PolySymbolQueryConfigurator`](%gh-ic%/platform/polySymbols/src/com/intellij/polySymbols/query/PolySymbolQueryConfigurator.kt)s with the addition of custom +[`PolyContextProvider`](%gh-ic%/platform/polySymbols/src/com/intellij/polySymbols/context/PolyContextProvider.kt). +As a result, for each kind of context, there is at most a single name assigned. +`PolyContext` can also be used outside the +[`PolySymbolQueryExecutor`](%gh-ic%/platform/polySymbols/src/com/intellij/polySymbols/query/PolySymbolQueryExecutor.kt) +as an efficient way to determine whether to enable or disable particular functionality in the IDE based on PSI or VFS context. + +### Query stack + +The stack is used as a scope for resolving symbols. +All scopes provided by +[`PolySymbolQueryConfigurator`](%gh-ic%/platform/polySymbols/src/com/intellij/polySymbols/query/PolySymbolQueryConfigurator.kt)s +together with the list of additional scopes passed as arguments to the query create an initial query stack. +Each time a symbol is matched, the list returned by `queryScope` property is added to the stack for any subsequent matches further right the pattern. + +## Declarations + +To provide locations of declarations of Poly Symbols, which are not +[`PsiSourcedPolySymbol`](%gh-ic%/platform/polySymbols/src/com/intellij/polySymbols/search/PsiSourcedPolySymbol.kt)s, +a dedicated +[`PolySymbolDeclarationProvider`](%gh-ic%/platform/polySymbols/src/com/intellij/polySymbols/declarations/PolySymbolDeclarationProvider.kt) +should be registered. +It should return a list of +[`PolySymbolDeclaration`](%gh-ic%/platform/polySymbols/src/com/intellij/polySymbols/declarations/PolySymbolDeclaration.kt)s +in a particular `PsiElement` at a particular offset. +Symbols may implement the [`PolySymbolDeclaredInPsi`](%gh-ic%/platform/polySymbols/src/com/intellij/polySymbols/utils/PolySymbolDeclaredInPsi.kt) +interface to avoid boilerplate related to declaration building. + +## References and Code Completion + +Usually, it is enough to provide a [`PolySymbolQueryScopeContributor`](%gh-ic%/platform/polySymbols/src/com/intellij/polySymbols/query/PolySymbolQueryScopeContributor.kt) for the [supported language features](polysymbols_integration.md#supported-language-features). +However, when implementing integration for a language feature, reference providers and code completions need to be implemented from scratch. + +To provide references, a +[`PsiPolySymbolReferenceProvider`](%gh-ic%/platform/polySymbols/src/com/intellij/polySymbols/references/PsiPolySymbolReferenceProvider.kt) +should be registered. +If references resolve to a single `PolySymbol`, even if it may be a composite `PolySymbol`, the `getReferencedSymbol` method should be implemented. +If the symbol reference is offset within the `PsiElement`, for example, within a string literal, the `getReferencedSymbolNameOffset` should also be implemented. +If there are multiple symbol references within the `PsiElement` and it is not possible to use a [`PolySymbolWithPattern`](%gh-ic%/platform/polySymbols/src/com/intellij/polySymbols/query/PolySymbolWithPattern.kt) to represent that, `getOffsetsToReferencedSymbols` should be overridden instead. +The `PsiPolySymbolReferenceProvider` should use `PolySymbolQueryExecutor` to produce the list of the symbols at the given location. + +Together with references, completion providers should also be implemented. +Due to the nature of Poly Symbol patterns, providers need to be implemented separately from reference contributions. +A regular `CompletionContributor` should be registered, which in turn should register a pattern for completion provider, which extends [`PolySymbolsCompletionProviderBase`](%gh-ic%/platform/polySymbols/backend/src/com/intellij/polySymbols/completion/PolySymbolsCompletionProviderBase.kt). + +## Documentation, Navigation, Find Usages, and Rename Refactoring + +These platform features are based on the reference resolve, so once the reference is resolved to a `PolySymbol`, it is up to implementations of the interface to provide particular support. +Override `getDocumentationTarget`, `getNavigationTargets` methods, or `searchTarget`, `renameTarget` properties to inform the platform about how it should use the symbol. +To customize symbols documentation generically, [`PolySymbolDocumentationCustomizer`](%gh-ic%/platform/polySymbols/src/com/intellij/polySymbols/documentation/PolySymbolDocumentationCustomizer.kt) should be implemented. + +## Semantic highlighting + +Poly Symbol framework supports semantic highlighting of symbols. +The simplest method is to return the name of `TextAttributesKey` from the `PolySymbol.get` method, when `PolySymbol.PROP_IJ_TEXT_ATTRIBUTES_KEY` property value is requested. +For a more generic approach, `PolySymbolHighlightingCustomizer` may be implemented. diff --git a/topics/reference_guide/custom_language_support/polysymbols_integration.md b/topics/reference_guide/custom_language_support/polysymbols_integration.md new file mode 100644 index 00000000000..3876179c43f --- /dev/null +++ b/topics/reference_guide/custom_language_support/polysymbols_integration.md @@ -0,0 +1,328 @@ + + +# Poly Symbols Integration with Language Features + + +How to integrate your Poly Symbols with a particular language feature. + +IDEs provide built-in support for Poly Symbols integration with the main language features of HTML, CSS, JavaScript, and TypeScript. +Contribution of static symbols can be achieved through Web Types or Custom Elements Manifest. +The dynamic symbols, as a result of source code analysis, should be contributed through [`PolySymbolQueryScopeContributor`](%gh-ic%/platform/polySymbols/src/com/intellij/polySymbols/query/PolySymbolQueryScopeContributor.kt). + +The concept of contributing symbols is similar to how code completion works. +Platform runs multiple code completion contributors to build a list of available items for a particular place in the code. +Later on,the list is displayed to the user. +Query executor, on the other hand, uses a list of contributed [`PolySymbolScope`](%gh-ic%/platform/polySymbols/src/com/intellij/polySymbols/query/PolySymbolScope.kt)s at a given location to either list all available symbols, get code completions, or match a name against the list of available symbols. + +The implementations should register query scope providers by calling the `registrar` parameter methods. +The registrar works as a builder, but each call creates a new instance, so you can reuse build stages, for example: + +```kotlin +registrar + .inFile(AstroFileImpl::class.java) + .inContext { it.framework == AstroFramework.ID } + .apply { + // Default scopes + forAnyPsiLocationInFile() + .contributeScopeProvider { + mutableListOf( + AstroFrontmatterScope(it.containingFile as AstroFile), + AstroAvailableComponentsScope(it.project) + ) + } + + // AstroStyleDefineVarsScope + forPsiLocation(CssElement::class.java) + .contributeScopeProvider { location -> + location.parentOfType() + ?.takeIf { + it.name.equals(HtmlUtil.STYLE_TAG_NAME, ignoreCase = true) + } + ?.let { listOf(AstroStyleDefineVarsScope(it)) } + ?: emptyList() + } + } +``` + +The order in which the builder methods are called does not affect the final performance. +Framework reorders conditions in the best way to efficiently match contributors with locations in the code. + +### A Symbol Referencing Pattern + +A common pattern for contributing symbols is to use a reference pattern to map from one kind of symbols to the other. +Let's say that we can produce a list of symbols representing message bundle file property keys. +Such symbols could have a qualified kind named: `message-bundle/properties`. +Let's say that these message bundle properties can be used as string literal parameters to some Java method calls. +A scope contributor would provide a scope containing all the `properties` symbols and a symbol with a reference pattern, which would map from `message-bundle/properties` to the ` java/string-literals ` kind. +A convenient way of defining such a symbol is to use the `ReferencingPolySymbol` class. + +As a result, we can say that in a particular place in the code, all provided message bundle properties should be treated as possible string literal values. +Such an approach allows symbol contributors to abstract from the actual implementation details of registering completion providers or reference providers in a particular language and focus on building the symbol model. + +## Supported Language Features + +### HTML + +#### Elements +{#html-elements} + +**Namespace**: `html` + +**Kind**: `elements` + +Poly Symbols representing available HTML elements. +HTML element symbols can be contributed statically or dynamically (through [`PolySymbolQueryScopeContributor`](%gh-ic%/platform/polySymbols/src/com/intellij/polySymbols/query/PolySymbolQueryScopeContributor.kt)). +The statically contributed symbols are available globally, depending on the context setting of the contributing Web Types file. + +For dynamic contributions, the contributors should be registered with the following `PsiElement` classes: +- [`HtmlTag`](%gh-ic%/xml/xml-psi-api/src/com/intellij/psi/html/HtmlTag.java) - Poly Symbols should represent available HTML elements. + The HTML tag's actual name should not be taken into account when building the scope. +- `CssElement` - Poly Symbols should represent available HTML elements within a particular CSS file. + +The matched Poly Symbol tag is taken as a scope for matching HTML attributes of the tag. + +#### Attributes +{#html-attributes} + +**Namespace**: `html` + +**Kind**: `attributes` + +Poly Symbols representing available HTML attributes. +HTML attribute symbols can be contributed statically or dynamically (through [`PolySymbolQueryScopeContributor`](%gh-ic%/platform/polySymbols/src/com/intellij/polySymbols/query/PolySymbolQueryScopeContributor.kt)). +The statically contributed symbols are available globally, depending on the context setting of the contributing Web Types file. +If the containing tag is matched to a Poly Symbol, it is added to the scope for attribute matching. + +For dynamic contributions, the contributors should be registered with the following `PsiElement` classes: +- [`XmlAttribute`](%gh-ic%/xml/xml-psi-api/src/com/intellij/psi/xml/XmlAttribute.java) - Poly Symbols should represent available HTML attributes for matching. + The HTML attribute's actual name should not be taken into account when building the scope. + However, the parent HTML tag and other attributes can be taken into account when building the scope. +- [`HtmlTag`](%gh-ic%/xml/xml-psi-api/src/com/intellij/psi/html/HtmlTag.java) - Poly Symbols should represent available HTML attributes for matching. + The HTML tag and other attributes can be taken into account when building the scope. + +Dedicated support for `PolySymbol` modifiers: +- `required` - if present, a warning will be shown if the attribute is missing. + Does not apply to `virtual` attributes. +- `optional` - during `PolySymbolMatch` modifiers merge, only one of `required` and `optional` modifiers will be present in the final set. + The `optional` modifier may be used to force the attribute to be not `required` +- `virtual` - specifies virtual attributes used by web frameworks. + Usually they are used during template compilation and missing from the final DOM. + +Dedicated support for `PolySymbol` `get` properties: +- `PROP_HTML_ATTRIBUTE_VALUE` - A special property to support symbols representing HTML attributes. + It can specify the kind (`plain`, `expression`, `no-value`), type (`boolean`, `number`, `string`, `enum`, `complex`, `of-match`), whether an attribute value is required, a default value, and the result type of value expression in the appropriate language. + If the `COMPLEX` type is set, the value of `langType` will be used, and if `OF_MATCH`, the type of the `symbol` will be used. + When merging information from several segments in the PolySymbolMatch, the first non-null property values take precedence. + By default - when properties are `null` - the attribute value is of plain type and is required. + +### CSS + +#### Properties +{#css-properties} + +**Namespace**: `css` + +**Kind**: `properties` + +Poly Symbols representing available CSS properties. [Custom CSS properties (variables)](https://developer.mozilla.org/en-US/docs/Web/CSS/Using_CSS_custom_properties) names should be prefixed with `--`. +CSS properties can be contributed statically or dynamically (through [`PolySymbolQueryScopeContributor`](%gh-ic%/platform/polySymbols/src/com/intellij/polySymbols/query/PolySymbolQueryScopeContributor.kt)). +The statically contributed symbols are available globally, depending on the context setting of the contributing Web Types file. + +Within a CSS file, the additional scope for matching properties is built from Poly Symbols matching HTML element names from terminal selectors from the enclosing ruleset. + +Within an HTML element `style` attribute value, an additional scope is built from Poly Symbols matching the enclosing HTML element. + +Scope for custom properties (variables) references (arguments for [`var()`](https://developer.mozilla.org/en-US/docs/Web/CSS/var) function) is built the same way +as for properties. +Only properties with names starting with `--` are taken into account. + +For dynamic contributions, the contributors should be registered with the following `PsiElement` classes: +- `CssDeclaration` - Poly Symbols should represent available CSS properties for matching. + The CSS declaration's actual name should not be taken into account when building the scope. + +#### Pseudo-elements +{#css-pseudo-elements} + +**Namespace**: `css` + +**Kind**: `pseudo-elements` + +Poly Symbols representing available [CSS pseudo-elements](https://developer.mozilla.org/en-US/docs/Web/CSS/Pseudo-elements). +Symbols names *should not* be prefixed with `::`. +CSS pseudo-elements can be contributed statically or dynamically (through [`PolySymbolQueryScopeContributor`](%gh-ic%/platform/polySymbols/src/com/intellij/polySymbols/query/PolySymbolQueryScopeContributor.kt)). +The statically contributed symbols are available globally, depending on the context setting of the contributing Web Types file. + +The additional scope for matching pseudo-elements is built from Poly Symbols matching HTML element name preceding the pseudo-element keyword. + +For dynamic contributions, the contributors should be registered with the following `PsiElement` classes: +- `CssPseudoSelector` - Poly Symbols should represent available CSS pseudo-elements for matching. + The CSS pseudo-element actual name should not be taken into account when building the scope. + +Alternatively, `CSS_PSEUDO_ELEMENTS_SYMBOL_QUERY_PATTERNS` constant may be used as the pattern. + +Dedicated support for `PolySymbol` `get` properties: +- `PROP_CSS_ARGUMENTS` - `true` if pseudo-element keyword accepts arguments. + +#### Pseudo-classes +{#css-pseudo-classes} + +**Namespace**: `css` + +**Kind**: `pseudo-classes` + +Poly Symbols representing available [CSS pseudo-classes](https://developer.mozilla.org/en-US/docs/Web/CSS/Pseudo-classes). +Symbols names *should not* be prefixed with `:`. +CSS pseudo-classes can be contributed statically or dynamically (through [`PolySymbolQueryScopeContributor`](%gh-ic%/platform/polySymbols/src/com/intellij/polySymbols/query/PolySymbolQueryScopeContributor.kt)). +The statically contributed symbols are available globally, depending on the context setting of the contributing Web Types file. + +The additional scope for matching pseudo-classes is built from Poly Symbols matching HTML element name preceding the pseudo-class keyword. + +For dynamic contributions, the contributors should be registered with the following `PsiElement` classes: +- `CssPseudoSelector` - Poly Symbols should represent available CSS pseudo-classes for matching. + The CSS pseudo-class actual name should not be taken into account when building the scope. + +Alternatively, `CSS_PSEUDO_CLASSES_SYMBOL_QUERY_PATTERNS` constant may be used as the pattern. + +Dedicated support for `PolySymbol` `get` properties: +- `PROP_CSS_ARGUMENTS` - `true` if pseudo-element keyword accepts arguments. + +#### Functions +{#css-functions} + +**Namespace**: `css` + +**Kind**: `functions` + +Poly Symbols representing available [CSS functions](https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Functions). +CSS functions can be contributed statically or dynamically (through [`PolySymbolQueryScopeContributor`](%gh-ic%/platform/polySymbols/src/com/intellij/polySymbols/query/PolySymbolQueryScopeContributor.kt)). +The statically contributed symbols are available globally, depending on the context setting of the contributing Web Types file. + +The additional scope for matching functions is built from Poly Symbols matching the CSS property name, the value of which is being calculated. + +For dynamic contributions, the contributors should be registered with the following `PsiElement` classes: +- `CssFunction` - Poly Symbols should represent available CSS functions for matching. + The CSS function actual name should not be taken into account when building the scope. + +Alternatively, `CSS_FUNCTIONS_SYMBOL_QUERY_PATTERNS` constant may be used as the pattern. + +#### Classes +{#css-classes} + +**Namespace**: `css` + +**Kind**: `classes` + +Poly Symbols representing available CSS classes. +Symbols names *should not* be prefixed with `.`. +CSS classes can be contributed statically or dynamically (through [`PolySymbolQueryScopeContributor`](%gh-ic%/platform/polySymbols/src/com/intellij/polySymbols/query/PolySymbolQueryScopeContributor.kt)). +The statically contributed symbols are available globally, depending on the context setting of the contributing Web Types file. + +Within a CSS file, an additional scope for matching classes is built from Poly Symbols matching the HTML element name preceding the class keyword. + +Within HTML attribute `class`, the additional scope for matching classes is built from Poly Symbols matching the enclosing HTML element name. + +For dynamic contributions, the contributors should be registered with the following `PsiElement` classes: +- `CssClass` - Poly Symbols should represent available CSS classes for matching. + The CSS class actual name should not be taken into account when building the scope. +- [`XmlAttributeValue`](%gh-ic%/xml/xml-psi-api/src/com/intellij/psi/xml/XmlAttributeValue.java) - Poly Symbols should represent available CSS classes for matching within the attribute value. + +Alternatively, `CSS_CLASSES_SYMBOL_QUERY_PATTERNS` constant may be used as the pattern. + +#### Parts +{#css-parts} + +**Namespace**: `css` + +**Kind**: `parts` + +Poly Symbols representing available HTML element parts for matching with [CSS `::part`](https://developer.mozilla.org/en-US/docs/Web/CSS/::part) pseudo-element. +CSS parts can be contributed statically or dynamically (through [`PolySymbolQueryScopeContributor`](%gh-ic%/platform/polySymbols/src/com/intellij/polySymbols/query/PolySymbolQueryScopeContributor.kt)). +The statically contributed symbols are available globally, depending on the context setting of the contributing Web Types file. + +Within a CSS file, an additional scope for matching classes is built from Poly Symbols matching HTML element name preceding the `::part` keyword. + +For dynamic contributions, the contributors should be registered with the following `PsiElement` classes: +- `CssTermImpl` - Poly Symbols should represent available CSS parts for matching. + The CSS part's actual name should not be taken into account when building the scope. + +Alternatively, `CSS_PARTS_SYMBOL_QUERY_PATTERNS` constant may be used as the pattern. + +### JavaScript + +#### String Literals +{#js-string-literals} + +**Namespace**: `js` + +**Kind**: `string-literals` + +Poly Symbols representing JavaScript or TypeScript string literals available in a particular location. +Only dynamically contributed string literal symbols (through [`PolySymbolQueryScopeContributor`](%gh-ic%/platform/polySymbols/src/com/intellij/polySymbols/query/PolySymbolQueryScopeContributor.kt)) have built-in support. + +For dynamic contributions, the contributors should be registered with the following `PsiElement` classes: +- a `JSLiteralExpression` +- an unqualified `JSReferenceExpression`, which parent is *not* `JSIndexedPropertyAccessExpression`, `JSCallExpression` or `JSProperty` + +Alternatively, `JS_STRING_LITERALS_SYMBOL_QUERY_PATTERNS` constant may be used as the pattern. + +#### Properties +{#js-properties} + +**Namespace**: `js` + +**Kind**: `properties` + +Poly Symbols represent properties of an object, which is a result of a JavaScript or TypeScript expression. +Only dynamically contributed properties symbols (through [`PolySymbolQueryScopeContributor`](%gh-ic%/platform/polySymbols/src/com/intellij/polySymbols/query/PolySymbolQueryScopeContributor.kt)) have built-in support. + +For dynamic contributions, the contributors should be registered with the following `PsiElement` classes: +- `JSObjectLiteralExpression` - Poly Symbols should represent expected properties +- `JSExpression` - Poly Symbols should represent available properties the expression's result. + Parent expression is `JSReferenceExpression` or `JSIndexedPropertyAccessExpression`. + +Alternatively, `JS_PROPERTIES_SYMBOL_QUERY_PATTERNS` constant may be used as the pattern. + +Dedicated support for `PolySymbol` modifiers: +- `required` - the JavaScript property is treated as non-optional +- `readonly` - the JavaScript property is treated as read-only + +Dedicated support for `PolySymbol` `get` properties: +- `PROP_JS_TYPE` - the type will be used in JavaScript type evaluator as the type of the property + +#### Symbols +{#js-symbols} + +**Namespace**: `js` + +**Kind**: `symbols` + +Poly Symbols representing JavaScript or TypeScript symbols available for resolve of an unqualified JavaScript reference expression. +Only dynamically contributed symbols (through [`PolySymbolQueryScopeContributor`](%gh-ic%/platform/polySymbols/src/com/intellij/polySymbols/query/PolySymbolQueryScopeContributor.kt)) have built-in support. + +For dynamic contributions, the contributors should be registered with the following `PsiElement` classes: +- an unqualified `JSReferenceExpression` - Poly Symbols should represent possible symbols to which JavaScript reference could resolve. + The reference to the actual name should not be taken into account when building the scope. + +Alternatively, `JS_SYMBOLS_SYMBOL_QUERY_PATTERNS` constant may be used as the pattern. + +Dedicated support for `PolySymbol` `get` properties: +- `PROP_JS_TYPE` - the type will be used in JavaScript type evaluator as the type of the symbol +- `PROP_JS_SYMBOL_KIND` - the kind of the symbol, one of [`JsSymbolSymbolKind`](%gh-ic%/platform/polySymbols/src-web/com/intellij/polySymbols/js/JsSymbolSymbolKind.kt) enum values. + The kind will be used to render the appropriate icon in the code completion popup + + *Integration with unqualified reference resolution is not available in TypeScript code* + +#### DOM Events +{#js-events} +**Namespace**: `js` + +**Kind**: `events` + +Poly Symbols representing available DOM events. +DOM events can be contributed statically or dynamically (through [`PolySymbolQueryScopeContributor`](%gh-ic%/platform/polySymbols/src/com/intellij/polySymbols/query/PolySymbolQueryScopeContributor.kt)). +The statically contributed symbols are available globally, depending on the context setting of the contributing Web Types file. + +The additional scope for matching DOM events is built from Poly Symbols matching enclosing HTML element name. + +For dynamic contributions, the contributors should be registered with the following `PsiElement` classes: +- [`HtmlTag`](%gh-ic%/xml/xml-psi-api/src/com/intellij/psi/html/HtmlTag.java) - Poly Symbols should represent available DOM events for matching. diff --git a/topics/reference_guide/custom_language_support/websymbols_web_types.md b/topics/reference_guide/custom_language_support/polysymbols_web_types.md similarity index 95% rename from topics/reference_guide/custom_language_support/websymbols_web_types.md rename to topics/reference_guide/custom_language_support/polysymbols_web_types.md index 9bd4836e7d6..7e84b37c4a9 100644 --- a/topics/reference_guide/custom_language_support/websymbols_web_types.md +++ b/topics/reference_guide/custom_language_support/polysymbols_web_types.md @@ -1,11 +1,11 @@ # Web Types - + -Web Types - contributing statically defined Web Symbols through JSONs. +Web Types - contributing statically defined Poly Symbols through JSONs. -Web Types is a JSON metadata format, which provides an easy way to contribute statically defined Web Symbols. +Web Types is a JSON metadata format, which provides an easy way to contribute statically defined Poly Symbols. The JSON Web Types detailed schema can be accessed by [following this link](https://github.com/JetBrains/web-types/blob/master/schema/web-types.json). The format is open source and IDE-agnostic by itself. @@ -119,8 +119,8 @@ To contribute a `foo` attribute, one could also write it in longer form: } ``` -Each Web Types contribution is represented in the Web Symbols framework by a -[`PsiSourcedWebSymbol`](%gh-ic%/platform/webSymbols/src/com/intellij/webSymbols/PsiSourcedWebSymbol.kt) +Each Web Types contribution is represented in the Poly Symbols framework by a +[`PsiSourcedPolySymbol`](%gh-ic%/platform/polySymbols/src/com/intellij/polySymbols/search/PsiSourcedPolySymbol.kt) object. All the Web Types contributions are mapped one-to-one, and custom properties are accessible through `properties` property. @@ -140,8 +140,8 @@ The property accepts a string or an array of strings with relative paths to Web IDE Plugin : You can ship Web Types JSON with your IDE plugin. -To point an IDE to its location, use and pass the file location in `source` attribute value. -With `enableByDefault` attribute, you can choose whether the Web Types file should be contributed to Web Symbols scope by default, +To point an IDE to its location, use and pass the file location in `source` attribute value. +With `enableByDefault` attribute, you can choose whether the Web Types file should be contributed to Poly Symbols scope by default, or only if an NPM package with the same name is present in the project. ## Special Properties diff --git a/topics/reference_guide/custom_language_support/rename_refactoring.md b/topics/reference_guide/custom_language_support/rename_refactoring.md index d630fe2240d..d045ca54630 100644 --- a/topics/reference_guide/custom_language_support/rename_refactoring.md +++ b/topics/reference_guide/custom_language_support/rename_refactoring.md @@ -19,7 +19,7 @@ Creating an entirely correct AST node from scratch is quite tricky. Thus, surprisingly, the easiest way to get the replacement node is to create a dummy file in the custom language so that it would contain the necessary node in its parse tree, build the parse tree and extract the required node from it. **Examples:** -- [`setName()`](%gh-ic%/plugins/properties/properties-psi-impl/src/com/intellij/lang/properties/psi/impl/PropertyImpl.java) implementation for a [Properties language plugin](%gh-ic%/plugins/properties) +- [`setName()`](%gh-ic%/plugins/properties/properties-common/src/com/intellij/lang/properties/psi/impl/PropertyImpl.java) implementation for a [Properties language plugin](%gh-ic%/plugins/properties) - [Custom Language Support Tutorial: Reference Contributor](reference_contributor.md) If a renamed reference extends [`PsiReferenceBase`](%gh-ic%/platform/core-api/src/com/intellij/psi/PsiReferenceBase.java), renaming is performed by invoking the [`ElementManipulator.handleContentChange()`](%gh-ic%/platform/core-api/src/com/intellij/psi/ElementManipulator.java), responsible for handling the content change and calculating the text range of reference inside the element. diff --git a/topics/reference_guide/custom_language_support/safe_delete_refactoring.md b/topics/reference_guide/custom_language_support/safe_delete_refactoring.md index 7074e9f3b15..a966af6646e 100644 --- a/topics/reference_guide/custom_language_support/safe_delete_refactoring.md +++ b/topics/reference_guide/custom_language_support/safe_delete_refactoring.md @@ -26,7 +26,7 @@ In addition to that, to support _Safe Delete_, a plugin needs to implement two t Deleting PSI elements is implemented by deleting the underlying AST nodes from the AST tree (which, in turn, causes the text ranges corresponding to the AST nodes to be deleted from the document). **Example:** -[`delete()`](%gh-ic%/plugins/properties/properties-psi-impl/src/com/intellij/lang/properties/psi/impl/PropertyImpl.java) implementation for a Property in [Properties language plugin](%gh-ic%/plugins/properties) +[`delete()`](%gh-ic%/plugins/properties/properties-common/src/com/intellij/lang/properties/psi/impl/PropertyImpl.java) implementation for a Property in [Properties language plugin](%gh-ic%/plugins/properties) If needed, it's possible to further customize how _Safe Delete_ is performed for a particular type of element (e.g., how references are searched) via [`SafeDeleteProcessorDelegate`](%gh-ic%/platform/lang-impl/src/com/intellij/refactoring/safeDelete/SafeDeleteProcessorDelegate.java). diff --git a/topics/reference_guide/custom_language_support/spell_checking.md b/topics/reference_guide/custom_language_support/spell_checking.md index b75fd3b7da9..777d88f1da4 100644 --- a/topics/reference_guide/custom_language_support/spell_checking.md +++ b/topics/reference_guide/custom_language_support/spell_checking.md @@ -19,7 +19,7 @@ and registering it in the - -# Web Symbols - - - -Web Symbols framework simplifies web technology development by utilizing Symbol API and supporting custom syntaxes. - - -> This API is available starting from 2022.3.1 and is currently in development and thus in an experimental state. -> -{style="warning"} - -Web Symbols is a framework built on top of the platform's [Symbol API](symbols.md). -Its primary use is to reduce boilerplate when building support for web technologies, -however one can take advantage of it for any kind of technology. - -Web Symbols API reduces work needed to provide reference resolution, find usages, documentation and rename refactoring. -It also provides an efficient JSON format (Web Types) for static symbol definitions. -Web Symbols core advantage, however, is the ability to evaluate symbol patterns. - -Web frameworks tend to have custom syntaxes to enable various things, -e.g. through HTML attribute name (see [Model Queries example](websymbols_implementation.md#model-queries-example) to see Vue directive syntax). -The pattern evaluator is able to recognize symbols in different sections of the element name and provide reference resolution, -documentation, usage occurrence, etc. -It also supports rename refactoring for symbols originating from source code. -Another advantage is the flexibility of Web Symbols query. -It is very easy to contribute new symbols from various sources, which works perfectly for multi-sourced -(e.g. source code, library code, Web Types) applications. - -Web Symbols API is not designed to create a support for new languages, but to rather work on meta -level, to support frameworks or libraries, which are giving additional meaning to the existing language features. -Currently, IDEs provide built-in integration for following language features (see [](websymbols_integration.md)): -- HTML: elements, attributes and attribute values -- CSS: properties, custom properties, functions, classes, pseudo-elements, pseudo-classes and parts -- JavaScript: string-literals, object properties, object literals and symbols (in JavaScript) - -There's also the option to write integration for other languages. - -Web Symbols framework provides also a convenient way to manage enablement of features through [`WebSymbolsContext` API](websymbols_context.md). - -The following sub-pages provide information on how to implement Web Symbols for plugins and how to -define them statically through JSON schemas: -- [](websymbols_implementation.md) -- [](websymbols_web_types.md) diff --git a/topics/reference_guide/custom_language_support/websymbols_implementation.md b/topics/reference_guide/custom_language_support/websymbols_implementation.md deleted file mode 100644 index e6bd7f1e1f7..00000000000 --- a/topics/reference_guide/custom_language_support/websymbols_implementation.md +++ /dev/null @@ -1,429 +0,0 @@ - - -# Implementing Web Symbols - - -Implementation details for the Web Symbols API. - -The core element of the framework is a -[`WebSymbol`](%gh-ic%/platform/webSymbols/src/com/intellij/webSymbols/WebSymbol.kt), -representing an entity in the Web Symbols model. -This symbol is characterized by `namespace`, `kind` and `name` properties, with its lifecycle encapsulated -within a single read action. -To ensure its survival between read actions, use `WebSymbol.createPointer()` to create a symbol pointer. -Provided the symbol remains valid, dereferencing the pointer will return a new instance of the symbol. -It should be noted that during a write action, the symbol might not survive a PSI tree commit. -Therefore, creating a pointer prior to the commit and dereferencing it post-commit is advised. - -The property `namespace` describes which language or concept (not tied to a particular language) the symbol belongs to, -and `kind` describes which group of symbols within that particular language or concept it belongs to. -Examples: - -- a CSS property: `namespace: CSS`, `kind: properties` -- a Java class: `namespace: Java`, `kind: classes` -- a plugin extension: `namespace: ij-plugin`, `kind: extensions` - -A Web Symbol can originate from source code analysis, or it can be a symbol statically defined -through [Web Types](websymbols_web_types.md) (JSON) or some other custom format. -In both cases, such a symbol can have some `source` defined. -Each symbol is treated by the framework the same, regardless of their origin. - -## General Properties - -`WebSymbol` has a number of properties which are used across IDE features: - -{style="full"} -`namespace` -: Describes which language or concept the symbol belongs to. - -`kind` -: Describes which group of symbols within the particular language or concept (namespace) the symbol belongs to. -The kind should be plural in form, e.g. "attributes". - -`name` -: The name of the symbol. If the symbol does not have a pattern, the name will be used as-is for matching. - -`origin` -: Specifies where this symbol comes from. -Besides descriptive information like framework, library, version, or default icon, -it also provides an interface to load symbol types and icons. - -`icon` -: An optional icon associated with the symbol, which is going to be used across the IDE. -If none is specified, a default icon of the `origin` will be used and if that’s not available, a default icon for symbol `namespace` and `kind`. - -`priority` -: Symbols with higher priority will have precedence over those with lower priority, when matching is performed. -Symbols with higher priority will also show higher on the completion list. - -`proximity` -: Provides an additional way to sort symbols in the code completion list within a particular priority. -The value must be a non-negative integer, and the higher proximity, the higher the symbol would be on the list. - -`apiStatus` -: *Since 2023.2 - replaces `deprecated` and `experimental` properties* -: Documents API status of the symbol. It is one of the sub-interfaces of [`WebSymbolApiStatus`](%gh-ic%/platform/webSymbols/src/com/intellij/webSymbols/WebSymbolApiStatus.kt): - `Stable`, `Experimental` or `Deprecated`. Deprecated symbols are appropriately highlighted in the code editor, code completion, and quick documentation. - -`deprecated` -: *Removed in 2023.2 - replaced with `apiStatus` property* -: Documents, whether the symbol is deprecated. Deprecated symbols are appropriately highlighted in the code editor, -code completion, and quick documentation. - -`experimental` -: *Removed in 2023.2 - replaced with `apiStatus` property* -: Documents, whether the symbol is considered an experimental feature and should be used with caution and might be -removed or its API altered in the future. - -`required` -: Whether this symbol is required. -What "is required" means depends on the symbol. -For instance, for an HTML attribute, it would mean that the attribute is required to be present for the particular HTML element. -For JavaScript property, it would mean that it is not optional, so it cannot be `undefined`. - -`defaultValue` -: If the symbol represents some property, variable, or anything that can hold a value, this property documents what is the default value. - -`type` -: The type of the symbol. The type can be interpreted only within the context of symbol origin and in regard to its namespace and kind. -The type may be a language type, coming from e.g., Java or TypeScript, or it may be any arbitrary value. -Usually a type would be associated with symbols, which can hold a value, or represent some language symbol, like class, method, etc. - -`psiContext` -: A PsiElement, which is a file or an element, which can be used to roughly locate the source of the symbol within a project to provide -a context for loading additional information, like types. -If the symbol is -[`PsiSourcedWebSymbol`](%gh-ic%/platform/webSymbols/src/com/intellij/webSymbols/PsiSourcedWebSymbol.kt) -(see [](#psisourcedwebsymbol)), then `psiContext` is equal to `source`. - -`properties` -: Various symbol properties. There should be no assumption on the type of properties. -Properties can be used by plugins to provide additional information on the symbol. -See [Web Types Special Properties](websymbols_web_types.md#special-properties) section for reference to the custom properties supported by IDEs. - -`presentation` -: Returns -[`TargetPresentation`](%gh-ic%/platform/core-api/src/com/intellij/platform/backend/presentation/TargetPresentation.kt) -used by -[`SearchTarget`](%gh-ic%/platform/lang-impl/src/com/intellij/find/usages/api/SearchTarget.kt) -and -[`RenameTarget`](%gh-ic%/platform/lang-impl/src/com/intellij/refactoring/rename/api/RenameTarget.kt). -Default implementations of -[`WebSymbolRenameTarget`](%gh-ic%/platform/webSymbols/src/com/intellij/webSymbols/refactoring/WebSymbolRenameTarget.kt) -and -[`WebSymbolSearchTarget`](%gh-ic%/platform/webSymbols/src/com/intellij/webSymbols/search/WebSymbolSearchTarget.kt) -use the `presentation` property. - -## Documentation Properties - -The following properties handle generation of -[Quick Doc](https://www.jetbrains.com/help/idea/viewing-reference-information.html#inline-quick-documentation) -in the IDE: - -{style="full"} -`description` -: An optional text, which describes the symbol's purpose and usage. -It is rendered in the documentation popup or view. - -`descriptionSections` -: Additional sections, to be rendered in the symbols’ documentation. -Each section should have a name, but the contents are optional. - -`docUrl` -: An optional URL to a website with detailed symbol's documentation - -`documentation` -: *Removed in 2023.1.1 - replaced by `createDocumentation()`* -: An interface holding information required to render documentation for the symbol. -To customize symbols documentation, one can override the method, or implement[`WebSymbolDocumentationCustomizer`](%gh-ic%/platform/webSymbols/src/com/intellij/webSymbols/documentation/WebSymbolDocumentationCustomizer.kt). -[`WebSymbolDocumentation`](%gh-ic%/platform/webSymbols/src/com/intellij/webSymbols/documentation/WebSymbolDocumentation.kt) -interface provides builder methods for customizing the documentation. -`with*` methods return a copy of the documentation with customized fields. - -## Query Related Properties - -The following properties are related to name matching and code completion queries: - -{style="full"} -`pattern` -: The pattern to match names against. -As a result of pattern matching, a [`WebSymbolMatch`](%gh-ic%/platform/webSymbols/src/com/intellij/webSymbols/query/WebSymbolMatch.kt) will be created. -A pattern may specify that a reference to other Web Symbols is expected in some part of it. -For such places, appropriate segments with referenced Web Symbols will be created and navigation, validation, and refactoring support are available out-of-the-box. - -`queryScope` -: When a pattern is being evaluated, matched symbols can provide additional scope for further resolution in the pattern. -By default, the `queryScope` returns the symbol itself - -`virtual` -: Some symbols represent only a framework syntax, which does not translate to a particular symbol in the runtime. -For instance, a Vue directive, which needs to be prefixed with `v-` will result in some special code generated, -but as such is not a real HTML attribute. This distinction allows us to ignore such symbols when looking for references. - -`abstract` -: Some symbols may have a lot in common with each other, and one can use abstract symbols as their super symbol. -For performance reasons, only statically defined symbols ([](websymbols_web_types.md), -[Custom Elements Manifest](https://github.com/webcomponents/custom-elements-manifest)) -can inherit from other statically defined symbols. -For dynamically defined symbols, regular class inheritance should be used. - -`extension` -: Specifies whether the symbol is an extension. -When matched along with a non-extension symbol, it can provide or override some properties of the symbol, or it can extend its scope contents. - -## HTML support - -`attributeValue` -: A special property to support symbols representing HTML attributes. -It can specify the kind (plain, expression, no-value), type (boolean, number, string, enum, complex, of-match), -whether an attribute value is required, a default value, and the result type of value expression in the appropriate language. -If `COMPLEX` type is set, the value of `langType` will be used and if `OF_MATCH`, the type of the `symbol` will be used. -When merging information from several segments in the WebSymbolMatch, first non-null property values take precedence. -By default - when properties are `null` - attribute value is of plain type and is required. - -## Methods -{#query-methods} - -{style="full"} -`createPointer()` -: Returns the pointer to the symbol, which can survive between read actions. -The dereferenced symbol should be valid, e.g., any PSI-based properties should return valid `PsiElement`s. - -`getModificationCount()` -: Symbols can be used in -[`CachedValue`](%gh-ic%/platform/core-api/src/com/intellij/psi/util/CachedValue.java)s -as dependencies. -If a symbol instance can mutate over time, it should properly implement this method. - -`isEquivalentTo()` -: Returns true if two symbols are the same or equivalent for resolve purposes. - -`adjustNameForRefactoring()` -: Web Symbols can have various naming conventions. -This method is used by the framework to determine a new name for a symbol based on its occurrence. - -`getDocumentationTarget()` -: *Since 2023.1.1* -: Used by the Web Symbols framework to get a [`DocumentationTarget`](%gh-ic%/platform/lang-impl/src/com/intellij/platform/backend/documentation/DocumentationTarget.kt), which handles documentation -rendering for the symbol. -The default implementation will use `createDocumentation()` to render the documentation. - -`createDocumentation()` -: *Since 2023.1.1 - replaces `documentation` property* -: Returns [`WebSymbolDocumentation`](%gh-ic%/platform/webSymbols/src/com/intellij/webSymbols/documentation/WebSymbolDocumentation.kt) - -an interface holding information required to render documentation for the symbol. -By default, its contents are built from the available Web Symbol information. To customize symbols documentation, one can override the method, or implement -[`WebSymbolDocumentationCustomizer`](%gh-ic%/platform/webSymbols/src/com/intellij/webSymbols/documentation/WebSymbolDocumentationCustomizer.kt). -: -[`WebSymbolDocumentation`](%gh-ic%/platform/webSymbols/src/com/intellij/webSymbols/documentation/WebSymbolDocumentation.kt) -interface provides builder methods for customizing the documentation. -`with*` methods return a copy of the documentation with customized fields. - - -## `PsiSourcedWebSymbol` - -A symbol should implement -[`PsiSourcedWebSymbol`](%gh-ic%/platform/webSymbols/src/com/intellij/webSymbols/PsiSourcedWebSymbol.kt) -if its declaration is a regular `PsiElement`, e.g., a variable or a declared type. -Once a symbol implements this interface, it can be searched and refactored together with the PSI element declaration. -In case a symbol is part of a `PsiElement` (for instance, being part of a string literal), -spans multiple PSI elements, or does not correlate one-to-one with a PSI element, -contribution of a dedicated declaration provider instead of implementing this interface is recommended. - -### Properties -{#psisourcedwebsymbol-properties} - -{style="full"} -`source` -: The `PsiElement`, which is the symbol declaration. - -## `CompositeWebSymbol` - -[`WebSymbolMatch`](%gh-ic%/platform/webSymbols/src/com/intellij/webSymbols/query/WebSymbolMatch.kt) -and some special symbols can have a name, which consists of other Web Symbols. - -### Properties -{#compositewebsymbol-properties} - -{style="full"} -`nameSegments` -: List of -[`WebSymbolNameSegment`](%gh-ic%/platform/webSymbols/src/com/intellij/webSymbols/WebSymbolNameSegment.kt). -Each segment describes a range in the symbol name. -Segments can be built of other Web Symbols and/or have related matching problems - missing required part, -unknown symbol name or be a duplicate of another segment. -See the [Model Queries Example](#model-queries-example) section for an example. - -## Web Symbols Scope - -Web Symbols are contained within a loose model built from Web Symbols scopes, each time anew for a particular context. -Each Web Symbol is also a -[`WebSymbolsScope`](%gh-ic%/platform/webSymbols/src/com/intellij/webSymbols/WebSymbolsScope.kt) -and it can contain other Web Symbols. -For instance, an HTML element symbol would contain some HTML attributes symbols, or a JavaScript class symbol would contain field and method symbols. -When configuring queries, Web Symbols scopes are added to the list to create an initial scope for symbols resolve. - -### Methods -{#websymbolsscope-methods} - -{style="full"} -`getSymbols()` -: Returns symbols within the scope. If provided `name` is `null`, no pattern evaluation will happen and all symbols of a particular -kind and from a particular namespace will be returned. - -`getCodeCompletions()` -: Returns code completions for symbols within the scope. - -`isExclusiveFor()` -: When scope is exclusive for a particular namespace and kind, resolve will not continue down the stack during pattern matching. - -`createPointer()` -: Returns the pointer to the symbol scope, which can survive between read actions. The dereferenced symbol scope should be valid. - -`getModificationCount()` -: Symbol scopes are used in CachedValues as dependencies for query executors. -If a symbol scope instance can mutate over time, it should properly implement this method. - -When implementing a scope containing many elements, an extension of -[`WebSymbolsScopeWithCache`](%gh-ic%/platform/webSymbols/src/com/intellij/webSymbols/WebSymbolsScopeWithCache.kt) is advised. -This structure caches the list of symbols and uses an efficient cache mechanism to speed up queries. -On extension of this class, it's only necessary to override `initialize()` and provide parameters to -the super constructor to specify the caching strategy for the results. - -## Model Queries - -Web Symbols can contain patterns, which allow to compose them from other Web Symbols. -To find which symbols match available patterns, we need to make a match query. -One can also run a code completion query, which will produce a list of valid completions in the provided context. - -To perform a query, create a -[`WebSymbolsQueryExecutor`](%gh-ic%/platform/webSymbols/src/com/intellij/webSymbols/query/WebSymbolsQueryExecutor.kt) -using -[`WebSymbolsQueryExecutorFactory`](%gh-ic%/platform/webSymbols/src/com/intellij/webSymbols/query/WebSymbolsQueryExecutorFactory.kt). -The query executor will be configured by all the registered -[`WebSymbolsQueryConfigurator`](%gh-ic%/platform/webSymbols/src/com/intellij/webSymbols/query/WebSymbolsQueryConfigurator.kt)'s -based on the provided PSI context. -Configurators will provide initial Web Symbol scopes, rules for calculating Web Symbols context, and rules for symbol names conversion. - -The result of the match query is a list of WebSymbols. -Some of them might be -[`WebSymbolMatch`](%gh-ic%/platform/webSymbols/src/com/intellij/webSymbols/query/WebSymbolMatch.kt)es. -Such objects represent complex matches when patterns are used. -Web Symbol Match has `nameSegments` property, which precisely describes how segments of the name relate to referenced Web Symbols and -whether there are any problems with resolution or the name itself. - -When working with code completion, one can query for the list of code completions. -To properly calculate completions, a position in the current text under completion is required. -As a result, a list of -[`WebSymbolCodeCompletionItem`](%gh-ic%/platform/webSymbols/src/com/intellij/webSymbols/completion/WebSymbolCodeCompletionItem.kt) -will be provided. - -### Example -{#model-queries-example} - -Let’s take a Vue directive as an example. -It is a special HTML attribute processed by the Vue framework in runtime or during compile, -which results in additional code being attached to the DOM element. -Its structure looks as follows: - -![JavaScript Example Image](websymbols_web_types.svg){ width="706"} - -An example of how Vue directive might be declared in Web Types is here. -Once a match query is run on `v-on:click.once.alt`, we will get a -[`WebSymbolMatch`](%gh-ic%/platform/webSymbols/src/com/intellij/webSymbols/query/WebSymbolMatch.kt) -with the following segments: - -1. `v-`: Vue directive pattern symbol -2. `on`: Vue `on` directive -3. `:` -4. `click`: DOM `click` event symbol -5. `.` -6. `once`: Vue `on` directive `once` modifier -7. `alt`: Vue `on` directive `alt` modifier - -### Patterns - -Usually one would create such elements using Web Types, but sometimes there might be a need to do that programmatically. - -To simplify resolution and make it less ambiguous, -a segment to match is selected by taking everything up to static prefixes of the following patterns. -Thus, if we want to have symbol references and regular expressions in the pattern, -they either have to terminate the pattern or must be followed by a static text. -A regular pattern static prefix is also considered a static text. - -There are seven types of patterns: - -1. String match: try to match an exact text, the match is case-sensitive -2. Regular expression match: try to match a regular expression, the match can be case-insensitive -3. Symbol reference placeholder: a symbol reference resolve will be attempted when this pattern is reached. - A resolve will be made by the symbols provider from an enclosing complex pattern. - If none of the symbols match the segment, the segment will have `UNKNOWN_SYMBOL` problem reported. - The matched symbol might be a WebSymbolMatch itself, which allows for nesting patterns. -4. Pattern sequence: a sequence of patterns. If some patterns are not matched, an empty segment with `MISSING_REQUIRED_PART` will be created. -5. Complex pattern: this pattern is called complex, because it makes several things: - - The provided patterns are treated as alternatives. - - It can have symbols resolver, which is used by nested symbol reference placeholder patterns. - - It allows adding an additional scope to resolve stack - - A complex pattern might be optional, in which case its absence is not reported as an error in an enclosing sequence or complex pattern - - The match can be repeated, and any duplicate segments might have `DUPLICATED` problem set - - It can override proximity and priority, which by default is based on priority and proximity of matched symbols. - - {style="alpha-lower"} -6. Completion auto popup: a special pattern, which works only in code completion queries. - It delimits the place where when creating code completion items, pattern evaluation should be stopped and `...` added. - Selecting such items will result in adding the prefix part, and then another code completion popup will open. - The pattern can be sticky, which means that the prefix will be shown in the nested code completion list. -7. Single symbol reference (*since 2023.2*): try to match text against the symbol name, but put a reference to another element. - -### Query Context - -When performing queries, some symbols should be excluded and others included in particular contexts. -For instance, if we have an Angular project, none of the Vue components should be available. -[`WebSymbolsContext`](%gh-ic%/platform/webSymbols/src/com/intellij/webSymbols/context/WebSymbolsContext.kt) -is created using rules provided by `WebSymbolsQueryConfigurator`s with the addition of custom -[`WebSymbolsContextProvider`](%gh-ic%/platform/webSymbols/src/com/intellij/webSymbols/context/WebSymbolsContextProvider.kt). -As a result, for each kind of context, there is at most a single name assigned. -`WebSymbolsContext` can also be used outside the -[`WebSymbolsQueryExecutor`](%gh-ic%/platform/webSymbols/src/com/intellij/webSymbols/query/WebSymbolsQueryExecutor.kt) -as an efficient way to determine whether to enable or disable particular functionality in the IDE based on PSI or VFS context. - -### Query stack - -The stack is used as a scope for resolving symbols. -All scopes provided by -[`WebSymbolsQueryConfigurator`](%gh-ic%/platform/webSymbols/src/com/intellij/webSymbols/query/WebSymbolsQueryConfigurator.kt)s -together with the list of additional scopes passed as arguments to the query create an initial query stack. -Each time a symbol is matched, the list returned by `queryScope` property is added to the stack for any subsequent matches further right the pattern. - -## Declarations, References, Search, Refactoring - -To provide locations of declarations of Web Symbols, which are not -[`PsiSourcedWebSymbol`](%gh-ic%/platform/webSymbols/src/com/intellij/webSymbols/PsiSourcedWebSymbol.kt)s, -a dedicated -[`WebSymbolDeclarationProvider`](%gh-ic%/platform/webSymbols/src/com/intellij/webSymbols/declarations/WebSymbolDeclarationProvider.kt) -should be registered. -It should return a list of -[`WebSymbolDeclaration`](%gh-ic%/platform/webSymbols/src/com/intellij/webSymbols/declarations/WebSymbolDeclaration.kt)s -in a particular `PsiElement` at a particular offset. - -Similarly, to provide references, a -[`PsiSymbolReferenceProvider`](%gh-ic%/platform/core-api/src/com/intellij/model/psi/PsiSymbolReferenceProvider.java) -should be registered. -It should return -[`WebSymbolReference`](%gh-ic%/platform/webSymbols/src/com/intellij/webSymbols/references/WebSymbolReference.kt) -objects from `PsiSymbolReferenceProvider.getReferences()`. - -To support search/finding usages, Web Symbol needs to implement -[`SearchTarget`](%gh-ic%/platform/lang-impl/src/com/intellij/find/usages/api/SearchTarget.kt) -or a -[`WebSymbolSearchTarget`](%gh-ic%/platform/webSymbols/src/com/intellij/webSymbols/search/WebSymbolSearchTarget.kt) -needs to be provided for it through a -[`SymbolSearchTargetFactory`](%gh-ic%/platform/lang-impl/src/com/intellij/find/usages/symbol/SymbolSearchTargetFactory.java). - -To support name refactoring, the -[`RenameTarget`](%gh-ic%/platform/lang-impl/src/com/intellij/refactoring/rename/api/RenameTarget.kt) -interface needs to be implemented, -or a -[`WebSymbolRenameTarget`](%gh-ic%/platform/webSymbols/src/com/intellij/webSymbols/refactoring/WebSymbolRenameTarget.kt) -needs to be provided for it through a -[`SymbolRenameTargetFactory`](%gh-ic%/platform/lang-impl/src/com/intellij/refactoring/rename/symbol/SymbolRenameTargetFactory.java). diff --git a/topics/reference_guide/custom_language_support/websymbols_integration.md b/topics/reference_guide/custom_language_support/websymbols_integration.md deleted file mode 100644 index 8b11ea9b347..00000000000 --- a/topics/reference_guide/custom_language_support/websymbols_integration.md +++ /dev/null @@ -1,321 +0,0 @@ - - -# Web Symbols Integration with Language Features - - -How to integrate your Web Symbols with a particular language feature. - -IDEs provide built-in support for Web Symbols integration with main language features of HTML, CSS, and JavaScript. -Contribution of static symbols can be achieved through Web Types or Custom Elements Manifest, -or by creating and registering a [`WebSymbolsQueryConfigurator`](%gh-ic%/platform/webSymbols/src/com/intellij/webSymbols/query/WebSymbolsQueryConfigurator.kt) extension. - -The implementation of [`WebSymbolsQueryConfigurator`](%gh-ic%/platform/webSymbols/src/com/intellij/webSymbols/query/WebSymbolsQueryConfigurator.kt) requires overriding `getScope()`. -This process involves the creation of a `WebSymbolScope` list, -depending on the provided `PsiElement` (`element` parameter) and `WebSymbolContext` (`context` parameter). -The following list of supported language features outlines the types of `PsiElement`s that can be expected -for each supported language feature. - -## Supported Language Features - -### HTML - -#### Elements -{#html-elements} - -**Namespace**: `html` - -**Kind**: `elements` - -Web Symbols representing available HTML elements. -HTML element symbols can be contributed statically or dynamically (through -[`WebSymbolsQueryConfigurator`](%gh-ic%/platform/webSymbols/src/com/intellij/webSymbols/query/WebSymbolsQueryConfigurator.kt)). -The statically contributed symbols are available globally, depending on the context setting of the contributing Web Types file. - -For dynamic contributions, the `WebSymbolsQueryConfigurator.getScope()`'s `element` parameter can be: -- [`HtmlTag`](%gh-ic%/xml/xml-psi-api/src/com/intellij/psi/html/HtmlTag.java) - Web Symbols should represent available HTML elements. The HTML tag's actual name should not be taken into account when building the scope. -- `CssElement` - Web Symbols should represent available HTML elements within a particular CSS file. - -The matched Web Symbol is taken as a scope for matching HTML attributes of the tag. - -#### Attributes -{#html-attributes} - -**Namespace**: `html` - -**Kind**: `attributes` - -Web Symbols representing available HTML attributes. -HTML attribute symbols can be contributed statically or dynamically (through [`WebSymbolsQueryConfigurator`](%gh-ic%/platform/webSymbols/src/com/intellij/webSymbols/query/WebSymbolsQueryConfigurator.kt)). -The statically contributed symbols are available globally, depending on the context setting of the contributing Web Types file. -If the containing tag is matched to a Web Symbol, it is added to the scope for attribute matching. - -For dynamic contributions, the `WebSymbolsQueryConfigurator.getScope()`'s `element` parameter can be: -- [`XmlAttribute`](%gh-ic%/xml/xml-psi-api/src/com/intellij/psi/xml/XmlAttribute.java) - Web Symbols should represent available HTML attributes for matching. The HTML attribute actual name should not be taken into account when building the scope. However, the parent HTML tag and other attributes can be taken into account when building the scope. -- [`HtmlTag`](%gh-ic%/xml/xml-psi-api/src/com/intellij/psi/html/HtmlTag.java) - Web Symbols should represent available HTML attributes for matching. The HTML tag and other attributes can be taken into account when building the scope. - -Dedicated support for `WebSymbol` interface properties: -- `required` - if `true`, a warning will be shown if the attribute is missing. Does not apply to `virtual` attributes. -- `default` - the default value of the attribute, if `attributeValue.default` is `null`. -- `attributeValue` - provides information about the attribute value, see [`attributeValue`](websymbols_implementation.md#html-support) reference. - -### CSS - -#### Properties -{#css-properties} - -**Namespace**: `css` - -**Kind**: `properties` - -Web Symbols representing available CSS properties. [Custom CSS properties (variables)](https://developer.mozilla.org/en-US/docs/Web/CSS/Using_CSS_custom_properties) names should be prefixed with `--`. -CSS properties can be contributed statically or dynamically (through [`WebSymbolsQueryConfigurator`](%gh-ic%/platform/webSymbols/src/com/intellij/webSymbols/query/WebSymbolsQueryConfigurator.kt)). -The statically contributed symbols are available globally, depending on the context setting of the contributing Web Types file. - -Within a CSS file, the additional scope for matching properties is built from Web Symbols matching HTML element names from terminal selectors from the enclosing ruleset. - -Within an HTML element `style` attribute value, an additional scope is built from Web Symbols matching the enclosing HTML element. - -Scope for custom properties (variables) references (arguments for [`var()`](https://developer.mozilla.org/en-US/docs/Web/CSS/var) function) is built the same way -as for properties. Only properties with names starting with `--` are taken into account. - -For dynamic contributions, the `WebSymbolsQueryConfigurator.getScope()`'s `element` parameter can be: -- `CssDeclaration` - Web Symbols should represent available CSS properties for matching. The CSS declaration actual name should not be taken into account when building the scope. - -#### Pseudo-elements -{#css-pseudo-elements} - -**Namespace**: `css` - -**Kind**: `pseudo-elements` - -Web Symbols representing available [CSS pseudo-elements](https://developer.mozilla.org/en-US/docs/Web/CSS/Pseudo-elements). -Symbols names *should not* be prefixed with `::`. -CSS pseudo-elements can be contributed statically or dynamically (through [`WebSymbolsQueryConfigurator`](%gh-ic%/platform/webSymbols/src/com/intellij/webSymbols/query/WebSymbolsQueryConfigurator.kt)). -The statically contributed symbols are available globally, depending on the context setting of the contributing Web Types file. - -The additional scope for matching pseudo-elements is built from Web Symbols matching HTML element name preceding the pseudo-element keyword. - -For dynamic contributions, the `WebSymbolsQueryConfigurator.getScope()`'s `element` parameter can be: -- `CssPseudoSelector` - Web Symbols should represent available CSS pseudo-elements for matching. The CSS pseudo-element actual name should not be taken into account when building the scope. - -Dedicated support for `WebSymbol` interface properties: -- `properties[WebSymbol.PROP_ARGUMENTS]` - `true` if pseudo-element keyword accepts arguments. - -#### Pseudo-classes -{#css-pseudo-classes} - -**Namespace**: `css` - -**Kind**: `pseudo-classes` - -Web Symbols representing available [CSS pseudo-classes](https://developer.mozilla.org/en-US/docs/Web/CSS/Pseudo-classes). -Symbols names *should not* be prefixed with `:`. -CSS pseudo-classes can be contributed statically or dynamically (through [`WebSymbolsQueryConfigurator`](%gh-ic%/platform/webSymbols/src/com/intellij/webSymbols/query/WebSymbolsQueryConfigurator.kt)). -The statically contributed symbols are available globally, depending on the context setting of the contributing Web Types file. - -The additional scope for matching pseudo-classes is built from Web Symbols matching HTML element name preceding the pseudo-class keyword. - -For dynamic contributions, the `WebSymbolsQueryConfigurator.getScope()`'s `element` parameter can be: -- `CssPseudoSelector` - Web Symbols should represent available CSS pseudo-classes for matching. The CSS pseudo-class actual name should not be taken into account when building the scope. - -Dedicated support for `WebSymbol` interface properties: -- `properties[WebSymbol.PROP_ARGUMENTS]` - `true` if pseudo-class keyword accepts arguments. - -#### Functions -{#css-functions} - -**Namespace**: `css` - -**Kind**: `functions` - -Web Symbols representing available [CSS functions](https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Functions). -CSS functions can be contributed statically or dynamically (through [`WebSymbolsQueryConfigurator`](%gh-ic%/platform/webSymbols/src/com/intellij/webSymbols/query/WebSymbolsQueryConfigurator.kt)). -The statically contributed symbols are available globally, depending on the context setting of the contributing Web Types file. - -The additional scope for matching functions is built from Web Symbols matching the CSS property name, the value of which is being calculated. - -For dynamic contributions, the `WebSymbolsQueryConfigurator.getScope()`'s `element` parameter can be: -- `CssFunction` - Web Symbols should represent available CSS functions for matching. The CSS function actual name should not be taken into account when building the scope. - -#### Classes -{#css-classes} - -**Namespace**: `css` - -**Kind**: `classes` - -Web Symbols representing available CSS classes. -Symbols names *should not* be prefixed with `.`. -CSS classes can be contributed statically or dynamically (through [`WebSymbolsQueryConfigurator`](%gh-ic%/platform/webSymbols/src/com/intellij/webSymbols/query/WebSymbolsQueryConfigurator.kt)). -The statically contributed symbols are available globally, depending on the context setting of the contributing Web Types file. - -Within CSS file, an additional scope for matching classes is built from Web Symbols matching HTML element name preceding the class keyword. - -Within HTML attribute `class` the additional scope for matching classes is built from Web Symbols matching the enclosing HTML element name. - -For dynamic contributions, the `WebSymbolsQueryConfigurator.getScope()`'s `element` parameter can be: -- `CssClass` - Web Symbols should represent available CSS classes for matching. The CSS class actual name should not be taken into account when building the scope. -- [`XmlAttributeValue`](%gh-ic%/xml/xml-psi-api/src/com/intellij/psi/xml/XmlAttributeValue.java) - Web Symbols should represent available CSS classes for matching within the attribute value. - -#### Parts -{#css-parts} - - - -**Namespace**: `css` - -**Kind**: `parts` - -Web Symbols representing available HTML element parts for matching with [CSS `::part`](https://developer.mozilla.org/en-US/docs/Web/CSS/::part) pseudo-element. -CSS parts can be contributed statically or dynamically (through [`WebSymbolsQueryConfigurator`](%gh-ic%/platform/webSymbols/src/com/intellij/webSymbols/query/WebSymbolsQueryConfigurator.kt)). -The statically contributed symbols are available globally, depending on the context setting of the contributing Web Types file. - -Within CSS file, an additional scope for matching classes is built from Web Symbols matching HTML element name preceding the `::part` keyword. - -For dynamic contributions, the `WebSymbolsQueryConfigurator.getScope()`'s `element` parameter can be: -- `CssTermImpl` - Web Symbols should represent available CSS parts for matching. The CSS part's actual name should not be taken into account when building the scope. - - -### JavaScript - -#### String Literals -{#js-string-literals} - - - -**Namespace**: `js` - -**Kind**: `string-literals` - -Web Symbols representing JavaScript or TypeScript string literals available in a particular location. -Only dynamically contributed string literal symbols (through [`WebSymbolsQueryConfigurator`](%gh-ic%/platform/webSymbols/src/com/intellij/webSymbols/query/WebSymbolsQueryConfigurator.kt)) have built-in support. - -The `WebSymbolsQueryConfigurator.getScope()`'s `element` parameter can be: -- a `JSLiteralExpression` -- an unqualified `JSReferenceExpression`, - which parent is *not* `JSIndexedPropertyAccessExpression`, `JSCallExpression` or `JSProperty` - -#### Properties -{#js-properties} - - - -**Namespace**: `js` - -**Kind**: `properties` - -Web Symbols represent properties of an object, which is a result of a JavaScript or TypeScript expression. -Only dynamically contributed properties symbols (through [`WebSymbolsQueryConfigurator`](%gh-ic%/platform/webSymbols/src/com/intellij/webSymbols/query/WebSymbolsQueryConfigurator.kt)) have built-in support. - -The `WebSymbolsQueryConfigurator.getScope()`'s `element` parameter can be: - - `JSObjectLiteralExpression` - Web Symbols should represent expected properties - - `JSExpression` - Web Symbols should represent available properties the expression's result. - Parent expression is `JSReferenceExpression` or `JSIndexedPropertyAccessExpression`. - -Dedicated support for `WebSymbol` interface properties: - - `type` - if the type is `JSType`, it will be used in JavaScript type evaluator as the type of the property - - `required` - the JavaScript property is treated as non-optional - - `properties[WebSymbol.PROP_READ_ONLY]` - the JavaScript property is treated as read-only - -#### Symbols -{#js-symbols} - - - -**Namespace**: `js` - -**Kind**: `symbols` - -Web Symbols representing JavaScript symbols available for resolve of an unqualified JavaScript reference expression. -Only dynamically contributed symbols (through [`WebSymbolsQueryConfigurator`](%gh-ic%/platform/webSymbols/src/com/intellij/webSymbols/query/WebSymbolsQueryConfigurator.kt)) have built-in support. - -The `WebSymbolsQueryConfigurator.getScope()`'s `element` parameter can be: -- an unqualified `JSReferenceExpression` - Web Symbols should represent possible symbols to which JavaScript reference could resolve. The reference to actual name should not be taken into account when building the scope. - -Dedicated support for `WebSymbol` interface properties: -- `type` - if the type is `JSType`, it will be used in JavaScript type evaluator as the type of the symbol -- `properties[WebSymbol.PROP_KIND]` - the kind of the symbol, one of [`WebSymbolJsKind`](%gh-ic%/platform/webSymbols/src/com/intellij/webSymbols/js/WebSymbolJsKind.kt) enum values. The kind will be used to render the appropriate icon in the code completion popup - - *Integration with unqualified reference resolution is not available in TypeScript code* - -#### DOM Events -{#js-events} -**Namespace**: `js` - -**Kind**: `events` - -Web Symbols representing available DOM events. -DOM events can be contributed statically or dynamically (through [`WebSymbolsQueryConfigurator`](%gh-ic%/platform/webSymbols/src/com/intellij/webSymbols/query/WebSymbolsQueryConfigurator.kt)). -The statically contributed symbols are available globally, depending on the context setting of the contributing Web Types file. - -The additional scope for matching DOM events is built from Web Symbols matching enclosing HTML element name. - -For dynamic contributions, the `WebSymbolsQueryConfigurator.getScope()`'s `element` parameter can be: -- [`HtmlTag`](%gh-ic%/xml/xml-psi-api/src/com/intellij/psi/html/HtmlTag.java) - Web Symbols should represent available DOM events for matching. - - -## Using Patterns for Domain-Specific Mappings - -When a language feature, such as an HTML element, is capable of representing an entity from a framework, -like a Vue component, it may be beneficial to use a custom symbol kind with a domain-specific name (for example, `vue-components`), -and establish a mapping from this to the language feature via a pattern: - -```json -{ - "contributions": { - "html": { - "elements": [ - { - "name": "Vue component", - "pattern": { - "items": "/html/vue-components" - }, - "attributes": [ - { - "name": "Component property", - "pattern": { - "or": [ - { - "items": "props", - "priority": "highest" - } - ] - }, - "value": { - "type": "of-match" - } - } - ] - } - ] - } - } -} -``` - -Note that in this example, attributes are produced from `html/props` symbols. -For Vue component, a set of named values, which can be provided to the component instance are called `props`. -Now, our Vue component definition can have a more domain-specific look: - -```json -{ - "contributions": { - "html": { - "vue-components": [ - { - "name": "MyVueComponent", - "description": "This is the component you always needed in your application", - "props": [ - { - "name": "listen-to", - "type": "string | HTMLElement | Document | Window | (() => HTMLElement)", - "description": "The scrolling element to listen to.", - "default": "document" - } - ] - } - ] - } - } -} -``` diff --git a/topics/reference_guide/embedded_terminal.md b/topics/reference_guide/embedded_terminal.md new file mode 100644 index 00000000000..dd8395f35a9 --- /dev/null +++ b/topics/reference_guide/embedded_terminal.md @@ -0,0 +1,162 @@ + + +# Embedded Terminal + + + +Describes In-IDE terminal API that allows interacting with the shell. + +IntelliJ Platform provides several terminal implementations: + +* Classic Terminal — the initial implementation that was the default option for a long time. +* [Reworked Terminal](https://blog.jetbrains.com/platform/2025/07/the-reworked-terminal-becomes-the-default-in-2025-2/) — the default option since the 2025.2 release. +* [Experimental Terminal](https://blog.jetbrains.com/idea/2024/02/the-new-terminal-beta-is-now-in-jetbrains-ides/) — the deprecated experimental implementation. + +All three implementations expose different APIs, and using _Reworked Terminal API_ (described on this page) is recommended. +Starting from this point, the _Terminal_ term will always refer to the _Reworked Terminal_. + +> The Terminal API is available since the 2025.3. +> It is under development and in the experimental status. +> Some aspects of it may change in future releases. +> +{style="warning" title="Experimental"} + +## Adding Dependency to the Terminal Plugin + +The Terminal API is provided by the _Terminal_ plugin bundled into the IntelliJ Platform-based IDEs. +To use the API, [add the dependency](plugin_dependencies.md) on the Terminal plugin (ID: `org.jetbrains.plugins.terminal`). + +## Getting a Terminal Instance + +The Terminal instance is represented by [`TerminalView`](%gh-ic-master%/plugins/terminal/frontend/src/com/intellij/terminal/frontend/view/TerminalView.kt). +Currently, the only place where the Reworked Terminal is available is the Terminal tool window +whose tabs are managed by the [`TerminalToolWindowTabsManager`](%gh-ic-master%/plugins/terminal/frontend/src/com/intellij/terminal/frontend/toolwindow/TerminalToolWindowTabsManager.kt). + +* Use `TerminalToolWindowTabsManager.getTabs()` to access already opened terminal tabs. +* Use `TerminalToolWindowTabsManager.createTabBuilder()` to create a new terminal tab. +* Use `TerminalView.DATA_KEY` to get the `TerminalView` from [action's](action_system.md#action-implementation) [`DataContext`](%gh-ic%/platform/core-ui/src/openapi/actionSystem/DataContext.java). + +## Accessing the Terminal Output + +The terminal has two output buffers: +- regular — used for executing commands and displaying their output +- alternative — usually used by "fullscreen" terminal applications like vim, nano, mc, and similar + +Both buffers are represented by [`TerminalOutputModel`](%gh-ic-master%/plugins/terminal/src/org/jetbrains/plugins/terminal/view/TerminalOutputModel.kt), +stored in [`TerminalOutputModelsSet`](%gh-ic-master%/plugins/terminal/src/org/jetbrains/plugins/terminal/view/TerminalOutputModelsSet.kt), +and can be accessed via `TerminalView.outputModels`. + +`TerminalOutputModel` is a read-only view of the terminal screen and the output history. +It can be thought of as a string that contains the currently displayed text and some previous history +that is removed ("trimmed") from time to time to avoid consuming too much memory. + +Because of trimming, this model uses absolute offsets to navigate in it. +They are represented by [`TerminalOffset`](%gh-ic-master%/plugins/terminal/src/org/jetbrains/plugins/terminal/view/TerminalOutputModel.kt) and [`TerminalLineIndex`](%gh-ic-master%/plugins/terminal/src/org/jetbrains/plugins/terminal/view/TerminalOutputModel.kt). +The currently available "window" has the length `TerminalOutputModel.textLength` +and is located between `TerminalOutputModel.startOffset` and `TerminalOutputModel.endOffset`. + +## Sending Input to the Shell + +Text can be sent to the shell using `TerminalView.sendText()`. +It will asynchronously send the text to the input stream of the process as is. + +Some additional options are provided via [`TerminalSendTextBuilder`](%gh-ic-master%/plugins/terminal/src/org/jetbrains/plugins/terminal/view/TerminalSendTextBuilder.kt) created with `TerminalView.createSendTextBuilder()`: + +* `shouldExecute()` - inserts the line wrap after the provided text to execute the command. + Prefer using this option rather than adding a line wrap manually to the text. +* `useBracketedPasteMode()` - wraps the provided text into a bracketed paste mode escape sequences (if it is supported by the shell). + It makes the shell treat the text like it was pasted from the clipboard. + And also ensure that the text won't be interpreted as a shell key binding. + +## Adding Actions to the Terminal + +To provide some custom handling for a shortcut in the terminal, +[`AnAction`](action_system.md#action-implementation) should be implemented. +But key events handling in the terminal are different compared to other places of the IDE, +so just registering an action in the [plugin.xml](plugin_configuration_file.md) won't be enough. + +Terminal has an option [*Override IDE shortcuts*](https://www.jetbrains.com/help/idea/settings-tools-terminal.html#application-settings) that limits the list of actions that can be executed +by shortcuts in the terminal to avoid conflicts of the IDE actions with the shell key bindings. +For example, it allows handling the Ctrl+R shortcut by the shell (and invoke search in commands history) instead of starting a [Run Configuration](run_configurations.md) in the IDE. + +To make an action available by shortcut in the terminal, +its ID should be provided to the terminal by implementing +[`TerminalAllowedActionsProvider`](%gh-ic-master%/plugins/terminal/frontend/src/com/intellij/terminal/frontend/view/TerminalAllowedActionsProvider.kt) +and registering it in . + +Consider the following example. + +MyTerminalAction.kt + +```kotlin +class MyTerminalAction : DumbAwareAction() { + override fun actionPerformed(e: AnActionEvent) { + val terminal = e.getData(TerminalView.DATA_KEY) ?: return + // perform the action in the terminal + } +} + +class MyTerminalAllowedActionsProvider : TerminalAllowedActionsProvider { + override fun getActionIds(): List { + return listOf("MyPlugin.MyTerminalAction") + } +} +``` + +plugin.xml + +```xml + + + + + + + + + +``` + +## Shell Integration + +When the shell process is started, the Terminal plugin injects shell scripts into its startup +to get information about the environment and subscribe to events. +For example, this allows tracking the positions of the prompt, command, and command output in the shell output. + +All APIs that rely on the shell integration are available in [`TerminalShellIntegration`](%gh-ic-master%/plugins/terminal/src/org/jetbrains/plugins/terminal/view/shellIntegration/TerminalShellIntegration.kt). +It can be accessed via `TerminalView.shellIntegrationDeferred`. +It is not available until the shell process is started and the shell integration is initialized. +To wait for the shell integration initialization, use `shellIntegrationDeferred.await()`. + +> The shell integration is currently available only for *Bash*, *Zsh* and *PowerShell*. +> `TerminalView.shellIntegrationDeferred.await()` call may never succeed for other shells. +> And it is not guaranteed that it will succeed even in supported shells because it highly depends on the user's shell configuration. +> Also, it depends on the state of the [*Shell Integration*](https://www.jetbrains.com/help/idea/settings-tools-terminal.html#application-settings) option in the Terminal settings. +> +{style="warning"} + +### Exploring Terminal Output Structure + +Information about previously executed commands and the current one is stored in [`TerminalBlocksModel`](%gh-ic-master%/plugins/terminal/src/org/jetbrains/plugins/terminal/view/shellIntegration/TerminalBlocksModel.kt). +This model is built of _Terminal Blocks_. + +Terminal block represents a range of text in the **regular** `TerminalOutputModel` +and some additional information about the content and meaning of this text. +Currently, there is a single type of the block: [`TerminalCommandBlock`](%gh-ic-master%/plugins/terminal/src/org/jetbrains/plugins/terminal/view/shellIntegration/TerminalBlocks.kt). + +`TerminalCommandBlock` represents the range of the shell output that can contain prompt, command and the command output. +Also, it provides additional metadata about the command, such as working directory, executed command, and exit code. +Note that not every command block is an executed terminal command. +Generally, it is just a range of text between the start of the shell prompt until the next prompt. + +### Listening for Command Execution + +To get notified when a command is executed in the shell, add a listener using `TerminalShellIntegration.addCommandExecutionListener()`. +Note that this listener is called only if the shell interprets the typed text as a valid command. +For example, it may not be called if the typed command text was blank and the user pressed Enter. + +To know the current state of the shell, for example, whether a command is executing or not, use `TerminalShellIntegration.outputStatus`. +Also, it allows listening for changes of the shell output state. + + diff --git a/topics/reference_guide/localization/internationalization.md b/topics/reference_guide/localization/internationalization.md index 7ff8946e0af..488b6888f5e 100644 --- a/topics/reference_guide/localization/internationalization.md +++ b/topics/reference_guide/localization/internationalization.md @@ -28,7 +28,7 @@ Consider using the following annotations: - [`@Nls`](%gh-java-annotations%/common/src/main/java/org/jetbrains/annotations/Nls.java) - for NLS strings. The `capitalization` attribute allows to specify required capitalization. - [`@NonNls`](%gh-java-annotations%/common/src/main/java/org/jetbrains/annotations/NonNls.java) - for non-NLS strings -- [`@NlsSafe`](%gh-ic%/platform/util/base/src/com/intellij/openapi/util/NlsSafe.java) - for NLS-safe strings +- [`NlsSafe`](%gh-ic%/platform/util/base/multiplatform/src/com/intellij/openapi/util/NlsSafe.kt) - for NLS-safe strings ### NLS Context Annotations @@ -37,10 +37,10 @@ For example, [`@InspectionMessage`](%gh-ic%/platform/analysis-api/src/com/intell NLS context annotations must be annotated with `@Nls` and they can define: - capitalization requirement - via `@Nls.capitalization` attribute -- [`@NlsContext`](%gh-ic%/platform/util/src/com/intellij/openapi/util/NlsContext.java) - specifies default prefix and suffix for property keys, which will be suggested by the I18nize hardcoded string literal quick fix provided by Java | Internationalization | Hardcoded strings inspection +- [`NlsContext`](%gh-ic%/platform/util/multiplatform/src/com/intellij/openapi/util/NlsContext.kt) - specifies default prefix and suffix for property keys, which will be suggested by the I18nize hardcoded string literal quick fix provided by Java | Internationalization | Hardcoded strings inspection The IntelliJ Platform provides NLS context annotations, including: -- general contexts: [`NlsContexts`](%gh-ic%/platform/util/src/com/intellij/openapi/util/NlsContexts.java) nested annotations +- general contexts: [`NlsContexts`](%gh-ic%/platform/util/multiplatform/src/com/intellij/openapi/util/NlsContexts.kt) nested annotations - action contexts: [`NlsActions`](%gh-ic%/platform/editor-ui-api/src/com/intellij/openapi/util/NlsActions.java) nested annotations - miscellaneous contexts: [`@InspectionMessage`](%gh-ic%/platform/analysis-api/src/com/intellij/codeInspection/util/InspectionMessage.java), diff --git a/topics/reference_guide/new_project_wizard.md b/topics/reference_guide/new_project_wizard.md index 0859721aa29..b6d8bca4b0c 100644 --- a/topics/reference_guide/new_project_wizard.md +++ b/topics/reference_guide/new_project_wizard.md @@ -40,7 +40,7 @@ The generator implementation must provide: **Examples:** - [`KotlinNewProjectWizard`](%gh-ic%/plugins/kotlin/project-wizard/idea/src/org/jetbrains/kotlin/tools/projectWizard/KotlinNewProjectWizard.kt) generating Kotlin projects -- [`PythonNewProjectWizard`](%gh-ic-master%/python/pluginJava/src/com/intellij/python/community/plugin/java/PythonNewProjectWizard.kt) generating Python projects +- [`PythonNewProjectWizard`](%gh-ic%/python/pluginJava/src/com/intellij/python/community/plugin/java/PythonNewProjectWizard.kt) generating Python projects ## Framework Project Generators diff --git a/topics/reference_guide/project_model/sdk.md b/topics/reference_guide/project_model/sdk.md index b64788d433c..711725dd5a1 100644 --- a/topics/reference_guide/project_model/sdk.md +++ b/topics/reference_guide/project_model/sdk.md @@ -33,7 +33,7 @@ Sdk projectSdk = ProjectRootManager.getInstance(project).getProjectSdk(); * To get the project-level SDK: ```java - Sdk projectSdk = ProjectRootManager.getInstance(project).getProjectSdkName(); + Sdk projectSdk = ProjectRootManager.getInstance(project).getProjectSdk(); ``` * To get the project-level SDK name: diff --git a/topics/reference_guide/settings_groups.md b/topics/reference_guide/settings_groups.md index 53444f67c73..944180cf2d9 100644 --- a/topics/reference_guide/settings_groups.md +++ b/topics/reference_guide/settings_groups.md @@ -75,7 +75,7 @@ The example below demonstrates a nested `configurable` declaration: id="com.intellij.sdk.tasks" displayName="Tasks" nonDefaultProject="true" - instance="com.intellij.sdk.TaskConfigurable"/> + instance="com.intellij.sdk.TaskConfigurable"> Alt+Shift+Enter. +To register `PopupDialogAction` and set up its basic attributes, invoke the Register Action quick fix. +To do this, hover the `PopupDialogAction` class name and click the quick fix link, or place the caret at the class name, press Alt+Enter, and select the quick fix. + Fill out the New Action form to set up the parameters for `PopupDialogAction`: ![New Action](new_action.png){width="800"} @@ -78,7 +80,7 @@ The fields of the form are: Clicking on the list of groups and typing invokes a search, such as "ToolsMenu". * Anchor - Where the menu action should be placed in the Tools menu relative to the other actions in that menu. -In this case, `PopupDialogAction` would be available in the Tools menu, it would be placed at the top, and would have no shortcuts. +In this case, `PopupDialogAction` would be available in the Tools menu, it would be placed at the top and would have no shortcuts. After finishing the New Action form and applying the changes, the [``](plugin_configuration_file.md#idea-plugin__actions) section of the plugin's plugins.xml file would contain: @@ -94,7 +96,7 @@ After finishing the New Action form and applying the changes, ``` -The [``](plugin_configuration_file.md#idea-plugin__actions__action) element declares the: +The [``](plugin_configuration_file.md#idea-plugin__actions__action) element declares: - Action ID (`id`) - Class Name (`class`) - Name (`text`) @@ -159,7 +161,7 @@ However, it confirms the new entry appears at Tools | Pop Dialog Action ## Developing the `AnAction` Methods -At this point, the new action `PopupDialogAction` is registered with the IntelliJ Platform and functions in the sense that `update()` and `actionPerformed()` are called in response to user interaction with the IDE Tools menu. +At this point, the new action `PopupDialogAction` is registered with the IntelliJ Platform and functions in the sense that `update()` and `actionPerformed()` are called in response to user interaction with the IDE Tools menu. However, neither method implements any code to perform useful work. This section describes adding useful code to these methods. diff --git a/topics/tutorials/build_system/configuring_plugin_project.md b/topics/tutorials/build_system/configuring_plugin_project.md index f2c5c5ea4bb..e5ec51e6714 100644 --- a/topics/tutorials/build_system/configuring_plugin_project.md +++ b/topics/tutorials/build_system/configuring_plugin_project.md @@ -30,7 +30,7 @@ Newer IDE releases might not be supported fully in older releases of Gradle Inte -By default, the Gradle plugin will build a plugin project against the IntelliJ Platform defined by the latest EAP snapshot of the IntelliJ IDEA Community Edition. +By default, the Gradle plugin will build a plugin project against the IntelliJ Platform defined by the latest EAP snapshot of the IntelliJ IDEA. If a matching version of the specified IntelliJ Platform is not available on the local machine, the Gradle plugin downloads the correct version and type. IntelliJ IDEA then indexes the build and any associated source code and JetBrains Java Runtime. diff --git a/topics/tutorials/build_system/creating_plugin_project.md b/topics/tutorials/build_system/creating_plugin_project.md index f7c16022706..e644926fa4f 100644 --- a/topics/tutorials/build_system/creating_plugin_project.md +++ b/topics/tutorials/build_system/creating_plugin_project.md @@ -127,7 +127,7 @@ repositories { // Read more: https://plugins.jetbrains.com/docs/intellij/tools-intellij-platform-gradle-plugin.html dependencies { intellijPlatform { - create("IC", "2024.2.6") + create("IC", "2024.3.6") testFramework(org.jetbrains.intellij.platform.gradle.TestFrameworkType.Platform) // Add necessary plugin dependencies for compilation here, example: @@ -138,7 +138,7 @@ dependencies { intellijPlatform { pluginConfiguration { ideaVersion { - sinceBuild = "242" + sinceBuild = "243" } changeNotes = """ @@ -166,7 +166,7 @@ tasks { * The Group from the [New Project](#create-ide-plugin) wizard is the `project.group` value * `repositories`: setup required repositories ([](tools_intellij_platform_gradle_plugin_repositories_extension.md)) * `dependencies`: - * define target IDE type (`IC`) and version (`2024.2.6`) ([](tools_intellij_platform_gradle_plugin_dependencies_extension.md#target-versions)) + * define target IDE type (`IC`) and version (`2024.3.6`) ([](tools_intellij_platform_gradle_plugin_dependencies_extension.md#target-versions)) * add dependency on the platform testing framework ([](tools_intellij_platform_gradle_plugin_dependencies_extension.md#testing)) * `pluginConfiguration`: [`since-build`](tools_intellij_platform_gradle_plugin_extension.md#intellijPlatform-pluginConfiguration-ideaVersion) and initial [change notes](tools_intellij_platform_gradle_plugin_extension.md#intellijPlatform-pluginConfiguration-changeNotes) * `sourceCompatibility` enforces using a 21 JDK diff --git a/topics/tutorials/code_inspections.md b/topics/tutorials/code_inspections.md index 3455118a7a5..8c0f3457b27 100644 --- a/topics/tutorials/code_inspections.md +++ b/topics/tutorials/code_inspections.md @@ -33,7 +33,7 @@ It illustrates the components for a custom inspection plugin: * Writing an HTML [description](#inspection-description) of the inspection for display in the inspection preferences panel. * Creating a [test](#inspection-test) for the implemented inspection and quick fix. -Although the code sample illustrates implementations of these components, it is often useful to see examples of inspections implemented in the [IntelliJ Community](%gh-ic%/README.md) code base. +Although the code sample illustrates implementations of these components, it is often useful to see examples of inspections implemented in the [IntelliJ Platform](%gh-ic%/README.md) code base. To identify a given inspection's implementation classes, try to find an inspection [by name](explore_api.md#search-for-symbol-names) or [by UI texts](explore_api.md#search-by-ui-text). Consider also searching for existing implementations in [IntelliJ Platform Explorer](https://jb.gg/ipe?extensions=com.intellij.localInspection). diff --git a/topics/tutorials/custom_language_support/prerequisites.md b/topics/tutorials/custom_language_support/prerequisites.md index 2e58bf9c3ae..63a2d1a3f94 100644 --- a/topics/tutorials/custom_language_support/prerequisites.md +++ b/topics/tutorials/custom_language_support/prerequisites.md @@ -8,15 +8,15 @@ ## Download and Install IntelliJ IDEA -Download and install either IntelliJ IDEA Ultimate or IntelliJ IDEA Community Edition from [here](https://www.jetbrains.com/idea/download/). +Download and install IntelliJ IDEA from [here](https://www.jetbrains.com/idea/download/). -## Check out Community Edition Source Files +## Check out IntelliJ Platform Source Files > While not required, having the full sources of the platform and all bundled plugins available for browsing allows finding related implementations. > {style="note"} -Download the IntelliJ IDEA Community Edition source files as described in the IntelliJ IDEA Community Edition [README](%gh-ic%/README.md) file. +Download the IntelliJ Platform source files as described in the IntelliJ IDEA [README](%gh-ic%/README.md) file. ## Install Required Plugins diff --git a/topics/tutorials/editor_basics/coordinates_system.md b/topics/tutorials/editor_basics/coordinates_system.md index 43ac06f625b..bab73184ab8 100644 --- a/topics/tutorials/editor_basics/coordinates_system.md +++ b/topics/tutorials/editor_basics/coordinates_system.md @@ -33,7 +33,8 @@ public class EditorAreaIllustration extends AnAction { @Override public void actionPerformed(@NotNull AnActionEvent event) { // Get access to the editor and caret model. update() validated editor's existence. - Editor editor = event.getRequiredData(CommonDataKeys.EDITOR); + Editor editor = event.getData(CommonDataKeys.EDITOR); + if (editor == null) return; CaretModel caretModel = editor.getCaretModel(); } } @@ -106,7 +107,8 @@ public class EditorAreaIllustration extends AnAction { @Override public void actionPerformed(@NotNull AnActionEvent event) { // Get access to the editor and caret model. - Editor editor = event.getRequiredData(CommonDataKeys.EDITOR); + Editor editor = event.getData(CommonDataKeys.EDITOR); + if (editor == null) return; CaretModel caretModel = editor.getCaretModel(); Caret primaryCaret = caretModel.getPrimaryCaret(); LogicalPosition logicalPos = primaryCaret.getLogicalPosition(); @@ -201,7 +203,8 @@ public class EditorAreaIllustration extends AnAction { public void actionPerformed(@NotNull AnActionEvent event) { // Get access to the editor and caret model. - Editor editor = event.getRequiredData(CommonDataKeys.EDITOR); + Editor editor = event.getData(CommonDataKeys.EDITOR); + if (editor == null) return; CaretModel caretModel = editor.getCaretModel(); // Getting the primary caret ensures we get the correct one of a possible many. diff --git a/topics/tutorials/editor_basics/editor_events.md b/topics/tutorials/editor_basics/editor_events.md index dd54d67b5de..6c4f022f4f8 100644 --- a/topics/tutorials/editor_basics/editor_events.md +++ b/topics/tutorials/editor_basics/editor_events.md @@ -25,7 +25,7 @@ The source code for the Java action class is [EditorHandlerIllustration](%gh-sdk For more information about creating action classes, see [](action_system.md), which covers the topic in depth. The `EditorHandlerIllustration` action is registered in the _editor_basic_ [`plugin.xml`](%gh-sdk-samples-master%/editor_basics/src/main/resources/META-INF/plugin.xml) file. -Note that this action class is registered to appear on the Editor context menu. +Note that this action class is registered to appear in the Editor context menu. ```xml @@ -71,7 +71,7 @@ public class EditorHandlerIllustration extends AnAction { ### Acquiring the Correct `EditorActionHandler` When the `EditorHandlerIllustration.actionPerformed()` method clones the caret, it should use the appropriate IntelliJ Platform [`EditorActionHandler`](%gh-ic%/platform/platform-api/src/com/intellij/openapi/editor/actionSystem/EditorActionHandler.java). -An instance of [`EditorActionManager`](%gh-ic%/platform/platform-api/src/com/intellij/openapi/editor/actionSystem/EditorActionManager.java) is required to obtain the correct `EditorActionHandler`. +An instance of [`EditorActionManager`](%gh-ic%/platform/platform-api/src/com/intellij/openapi/editor/actionSystem/EditorActionManager.java) is required to get the correct `EditorActionHandler`. The `EditorActionManager` class provides a static method to do this. To request the correct `EditorActionHandler` from `EditorActionManager`, consult the [`IdeActions`](%gh-ic%/platform/ide-core/src/com/intellij/openapi/actionSystem/IdeActions.java) interface for the correct constant to pass into the `EditorActionManager.getActionHandler()` method. @@ -81,8 +81,8 @@ Based on that constant, the `EditorActionManager` returns an instance of [`Clone ```java // Snippet from EditorHandlerIllustration.actionPerformed() EditorActionManager actionManager = EditorActionManager.getInstance(); -EditorActionHandler actionHandler = - actionManager.getActionHandler(IdeActions.ACTION_EDITOR_CLONE_CARET_BELOW); +EditorActionHandler actionHandler = actionManager.getActionHandler( + IdeActions.ACTION_EDITOR_CLONE_CARET_BELOW); ``` ### Using an `EditorActionHandler` to Clone the Caret @@ -93,12 +93,14 @@ To clone the caret requires only calling the `EditorActionHandler.execute()` met public class EditorHandlerIllustration extends AnAction { @Override public void actionPerformed(@NotNull AnActionEvent event) { - Editor editor = event.getRequiredData(CommonDataKeys.EDITOR); + Editor editor = event.getData(CommonDataKeys.EDITOR); + if (editor == null) return; EditorActionManager actionManager = EditorActionManager.getInstance(); - EditorActionHandler actionHandler = - actionManager.getActionHandler(IdeActions.ACTION_EDITOR_CLONE_CARET_BELOW); + EditorActionHandler actionHandler = actionManager.getActionHandler( + IdeActions.ACTION_EDITOR_CLONE_CARET_BELOW); actionHandler.execute(editor, - editor.getCaretModel().getPrimaryCaret(), event.getDataContext()); + editor.getCaretModel().getPrimaryCaret(), + event.getDataContext()); } } ``` @@ -106,7 +108,7 @@ public class EditorHandlerIllustration extends AnAction { ## Creating a Custom `TypedActionHandler` The [`TypedActionHandler`](%gh-ic%/platform/platform-api/src/com/intellij/openapi/editor/actionSystem/TypedActionHandler.java) interface is the basis for classes that handle keystroke events from the editor. -Custom implementations of the class are registered to handle editor keystroke events, and receive a callback for each keystroke. +Custom implementations of the class are registered to handle editor keystroke events and receive a callback for each keystroke. The steps below explain how to use `TypedActionHandler` to customize the behavior of the editor when keystroke events are received. ### Implementing a Custom `TypedActionHandler` Class @@ -126,13 +128,12 @@ So although a method on the `Document` interface does the `String` insertion, th ```java final class MyTypedHandler implements TypedActionHandler { @Override - public void execute(@NotNull Editor editor, - char c, + public void execute(@NotNull Editor editor, char c, @NotNull DataContext dataContext) { Document document = editor.getDocument(); Project project = editor.getProject(); - Runnable runnable = () -> document.insertString(0, "editor_basics\n"); - WriteCommandAction.runWriteCommandAction(project, runnable); + WriteCommandAction.runWriteCommandAction(project, + () -> document.insertString(0, "editor_basics\n")); } } ``` @@ -158,4 +159,4 @@ public class EditorHandlerIllustration extends AnAction { Placing the registration code in the `EditorHandlerIllustration` class is somewhat arbitrary in the sense that the registration of `MyTypedHandler` has nothing to do with the `EditorHandlerIllustration` class. However, the `EditorHandlerIllustration` class is convenient because as an action it gets instantiated at application startup. On instantiation, the `static` block of code in `EditorHandlerIllustration` gets evaluated. -In the `editor_basics` code sample any of the `AnAction` derived classes would work for registering `MyTypedHandler`. +In the `editor_basics` code sample, any of the `AnAction` derived classes would work for registering `MyTypedHandler`. diff --git a/topics/tutorials/editor_basics/working_with_text.md b/topics/tutorials/editor_basics/working_with_text.md index 7d91bc8504a..40c439b4120 100644 --- a/topics/tutorials/editor_basics/working_with_text.md +++ b/topics/tutorials/editor_basics/working_with_text.md @@ -8,7 +8,7 @@ This tutorial shows how to use actions to access a caret placed in a document op Using information about the caret, replace selected text in a document with a string. The approach in this tutorial relies heavily on creating and registering actions. -To review the fundamentals of creating and registering actions, refer to [](action_system.md) tutorial. +To review the fundamentals of creating and registering actions, refer to the [](action_system.md) tutorial. Multiple examples are used from the [editor_basics](%gh-sdk-samples-master%/editor_basics) plugin code sample from the IntelliJ Platform SDK. It may be helpful to open that project in an IntelliJ Platform-based IDE, build the project, run it, select some text in the editor, and invoke the **Editor Replace Text** menu item on the editor context menu. @@ -22,7 +22,7 @@ The source code for the Java class in this example is [EditorIllustrationAction] To register the action, we must add the corresponding elements to the [``](plugin_configuration_file.md#idea-plugin__actions) section of the plugin configuration file [plugin.xml](%gh-sdk-samples-master%/editor_basics/src/main/resources/META-INF/plugin.xml). For more information, refer to the [](creating_actions_tutorial.md#registering-a-custom-action) section. -The `EditorIllustrationAction` action is registered in the group `EditorPopupMenu` so it will be available from the context menu when focus is on the editor: +The `EditorIllustrationAction` action is registered in the group `EditorPopupMenu` so it will be available from the context menu when the focus is on the editor: ```xml Correct + ![A notification with the body only about the workspace being restored after branch checkout](notification_balloon_body_only_correct.png){width=706} Incorrect + ![The same notification as above but with duplicating information in the title](notification_balloon_body_only_incorrect.png){width=706} #### Long messages are collapsed @@ -157,9 +159,11 @@ If the notification reports an error or warning, always provide an action to hel If no actions are available, provide more details in the body text: how to fix or what was the cause. Correct + ![A notification about a plugin being incompatible with the current IDE version with a suggestion to update the plugin](notification_balloon_error_actions_text_correct.png){width=706} Incorrect + ![The name notification but without the suggestion to update the plugin](notification_balloon_error_actions_text_incorrect.png){width=706} diff --git a/topics/ui/controls/checkbox.topic b/topics/ui/controls/checkbox.topic index 9b081f539f4..b46a0725798 100644 --- a/topics/ui/controls/checkbox.topic +++ b/topics/ui/controls/checkbox.topic @@ -25,13 +25,13 @@

    If only one option in a group can be selected, use radio button:

    - -
    + Incorrect - A radio button group with only one selected option possible + A radio button group with only one selected option possible + Correct - Two radio buttons with clear labels + Two radio buttons with clear labels
    @@ -39,13 +39,13 @@ and label them accordingly:

    - -
    + Incorrect - A radio button group with only one selected option possible + A radio button group with only one selected option possible + Correct - Two radio buttons with clear labels + Two radio buttons with clear labels
    @@ -55,12 +55,12 @@

    A label accompanies each checkbox and is placed on the right side.

    - - @@ -70,12 +70,12 @@

    If a label is long, split it into two lines. Use HTML formatting for that. Avoid labels that take more than two lines. See recommendations on writing concise labels below.

    - Correct + CorrectA correct checkbox with the label on the right - Incorrect + IncorrectAn incorrect checkbox with the label on the left
    - - diff --git a/topics/ui/controls/icon_button.md b/topics/ui/controls/icon_button.md index 62df9f2d17c..1a0867811ed 100644 --- a/topics/ui/controls/icon_button.md +++ b/topics/ui/controls/icon_button.md @@ -1,4 +1,4 @@ - + # Icon Button @@ -10,73 +10,51 @@ -A toolbar icon button is an icon that appears on a toolbar. - -Icon button - -## Types - -

    There are three types of toolbar icon buttons:

    - -An action button triggers an action immediately on clicking it, e.g., the Open button. - -A toggle button switches the state on clicking it, e.g., a button to show and hide warnings in the output tree. - -![](toggle.png){width=143} - -A drop-down button has an arrow icon in the bottom right corner and opens a menu with actions or checkboxes. - -[//]: # (TODO: Use [menu list](menu_list.md) guidelines for drop-down buttons.) - -![](drop-down.png){width=284} +
    - Correct + CorrectA correct checkbox with the label on the right - Incorrect + IncorrectAn incorrect checkbox with the label on the left
    + + + + +
    Using links instead of buttons + A toolbar icon button contains only an icon. There are three types of icon buttons: + +
  • An action triggers immediately.
  • +
  • A toggle switches between on and off states.
  • +
  • A drop-down opens a menu.
  • +
    +
    ## When to use -Follow the rules for [toolbar](toolbar.md#what-items-to-add-on-toolbar). +Follow the guidelines for the [Toolbar](toolbar.md#what-items-to-add-on-toolbar). ## How to use -Provide a recognizable icon. Use an [existing icon](https://intellij-icons.jetbrains.design) or create a new one using [icon guidelines](icons_style.md). +### Icon +Use an [existing icon](https://intellij-icons.jetbrains.design) or create a new one following the [icon guidelines](icons_style.md). -Provide a short and descriptive name for a toolbar icon button. Show a tooltip with the button name on mouse hover. -Include a shortcut if there is one. See [Context help](context_help.md) for details. - -![](tooltip.png){width=163} - -Highlight a toolbar icon button on mouse hover. Highlight a toolbar icon button with a brighter color on clicking it. - -* Toggle buttons remain highlighted when they are in the switched on mode. Toggled on buttons do not change color on hover. - -* Drop-down buttons remain highlighted while the menu is opened. - -![](states.png){width=183} - -If an action is not available in this context, disable the corresponding button and gray out the icon. -For toolbar drop-down buttons, disable the arrow icon as well. -Do **not** highlight a disabled icon on mouse hover. +### Tooltip + + + + + +
    Using links instead of buttonsAlways provide a tooltip for an icon button. Include a shortcut if there is one. See Tooltip for details.
    -## Sizes and placement +### States + + + + + +
    Using links instead of buttonsWhen an action is not available in a particular context, disable the icon button.
    -Icons size is 16×16px, icon selection is 22×22px. +### Filter badge +Using links instead of buttons -For guidelines on the space between toolbar icon buttons see [Toolbar](toolbar.md). +For filter actions, show a badge over an icon when a non-default option is selected. The badge helps to see if the content is in its default state or filtered. - +Search option icons have a more noticeable pressed state to allow quickly seeing what affects the search results. See [Search options](search_field.md#search-options) for details. diff --git a/topics/ui/controls/input_field.md b/topics/ui/controls/input_field.md index fa847fabafe..03eef0412c6 100644 --- a/topics/ui/controls/input_field.md +++ b/topics/ui/controls/input_field.md @@ -12,182 +12,241 @@ An input field allows users to enter or edit a text line using the keyboard. -![](input_field_example.png){width=170} +![](input.png){width=706} ## When to use Use an input field if it’s not possible to enumerate the most likely values. Otherwise, use a [combo box](combo_box.md) or a [drop-down list](drop_down.md). -If input has to be in a specific format, use one of the following controls: + + + + + + + + + +
    CorrectIncorrect
    -* If the previous user input must be preserved, use a [combo box](combo_box.md). -* Use a [text area](text_area.md) for long (commit message) or multi-line (code snippet) input. If place is constrained, use an [expandable input field](#input-field-types). -* Use a slider if a precise value is not required, or if it’s possible to provide feedback on the effect of setting changes. If place is constrained, use an input field. -* Use a [search field](search_field.md) to input a search query. -* Use calendar to set a date. -* Use color box to choose a color. +## When not to use -## How to use +### Previous input is saved -### Label +If the previous user input must be preserved, use a [combo box](combo_box.md). -A label accompanies each input field and indicates the information type. +![](combobox_when_to_use_1.png){width=706} + +### Large input + +Use a [text area](text_area.md) for long or multi-line input. + +![](input_text_area.png){width=706} + +### Space is limited + +If the place is constrained, use an expandable input field [`ExpandableTextField`](%gh-ic%/platform/platform-api/src/com/intellij/ui/components/fields/ExpandableTextField.java). +For more details, see [Expand button](built_in_button.md#expand-a-field). + +![](input_text_input_expand.png){width=706} + +### Many predefined values + +If there are many predefined values (for example, code snippets, commit author), add completion to the input field [`TextFieldWithCompletion`](%gh-ic%/platform/platform-impl/src/com/intellij/util/textCompletion/TextFieldWithCompletion.java). Show the completion popup when the user starts typing. + +![](input_completion.png){width=706} + +### Built-in buttons + +Use [built-in buttons](built_in_button.md) to help the user enter data. For example, to browse the disk. + +### Search -Labels should be [short and descriptive](writing_short.md). +Use a [search field](search_field.md) to input a search query. -Write the label either as a noun and end it with a colon: +![](input_search.png){width="706"} -![](label_noun.png){width=153} +### Password -Or as a phrase with no ending punctuation: +If input data is secured, replace it with dots via [`JBPasswordField`](%gh-ic%/platform/platform-api/src/com/intellij/ui/components/JBPasswordField.java). + +![](input_password.png){width=706} + + -![](label_sentence.png){width=247} +### Choosing a color -Do **not** use labels to tell users what to do: +Use a color box to choose a color. -![](user_action.png){width=186} +![](input_colour_box.png){width="706"} + +## How to use + +### Label + +A label accompanies each input field and indicates the information type. -Use sentence-style capitalization. +#### General rules -If there are several input fields on a form, it’s recommended to make labels approximately the same length to avoid gaps between labels and fields. For example: +* Labels should be [short and descriptive](writing_short.md). +* Write the label as a noun and end it with a colon. +* Don't use labels to tell users what to do. +* Use [sentence-style capitalization](capitalization.md#sentence). - +
    - - + + +
    IncorrectCorrectCorrectIncorrect
    + +#### Label as a phrase + +When writing a label as a phrase, don't use colon and ending punctuation. + + + + + + +
    CorrectIncorrect
    + +#### Grouped input fields + +If there are several input fields in a form, make labels approximately the same length to avoid gaps between labels and fields. + + - - + +
    CorrectIncorrect
    -If an input field is disabled, disable the label too: +#### Disabled state + +If an input field is disabled, disable the label too. + +![](input_disabled.png){width=706} -![](label_disabled.png){width=153} +#### Selectable label Make the label text selectable. The user may want to search for this option on the Internet or to send a question to support. +![](input_label_selected.png){width=706} + +#### Positioning a label + Place the label on the left or above the input field. For more details, see the [Layout](layout.md) topic. + + + + + +
    CorrectCorrect
    + ### Placeholder -Placeholder is grey text placed inside an input field. Follow these rules: +Placeholder is gray text placed inside an input field. To show placeholder text, use `JBTextField.getEmptyText().setText(...)`. +#### General rules {id="placeholder-general-rules"} * Use sentence-style capitalization. -* Do **not** use ending punctuation or ellipsis. +* Don't use ending punctuation or ellipsis. * Hide the placeholder when the user starts typing, not when the input field gets the focus. -To show placeholder text, use `JBTextField.getEmptyText().setText(...)`. +#### Optional input field Use the placeholder to indicate that an input field is optional. -![](placeholder_optional.png){width=397} +![](input_placeholder_optional.png){width=706} -Use the placeholder to show the default value: +#### Default values -![](placeholder_default.png){width=247} +Use the placeholder to show the default value. -If the user overwrites the value, it can be restored by removing the new value from the input field or by clicking the "Reset to default" link on the right: +![](input_placeholder_default.png){width=706} -![](placeholder_reset.png){width=361} +If the user overwrites the value, it can be restored by removing the new value from the input field or by clicking the Reset to default link on the right. -Do **not** use the placeholder to show examples. The user can get the impression that the field is already filled. Provide examples or explanation under the input field (see [Context help](context_help.md)): +![](input_placeholder_default_reset.png){width=706} - - - - - +#### Showing examples + +Don't use the placeholder to show examples because the user can get the impression that the field is already filled. Provide examples or explanation under the input field (see [Context help](context_help.md)): + +
    IncorrectCorrect
    - - + +
    CorrectIncorrect
    -Do **not** use the placeholder as the field label. After the field has been filled, it is difficult to understand its purpose. +#### Don't use placeholders as labels -![](placeholder_label.png){width=100} +Don't use the placeholder as the field label. After the field has been filled, it is difficult to understand its purpose. + + + + + + +
    CorrectIncorrect
    ### Prefilled value Pre-fill the field if it has the default or a frequently used value. Use the default text color for pre-filled values: -![](prefill.png){width=152} +![](input_prefilled.png){width=706} + +When naming a default entity like scope or notebook which can have multiple entities in a group, pre-fill it using the entity name with a sequential number: scope-1, scope-2, etc. -Do **not** prefill with "Unnamed". It takes time to read it and does not help the user to fill the form. +Don't use Unnamed as a prefilled value. It takes time to read it and does not help the user to fill the form. -![](prefill_unnamed.png){width=535} + + + + + +
    CorrectIncorrect
    ### Field focus When an input field gets the focus, place the caret at the end of the text: -![](focus_end.png){width=321} +![](input_focus.png){width=706} If users are more likely to re-enter the entire value, select the whole text when the field gets the focus: -![](focus_all.png){width=274} - -### Input field types - -If the input text can be long and the place is constrained, use an expandable input field [`ExpandableTextField`](%gh-ic%/platform/platform-api/src/com/intellij/ui/components/fields/ExpandableTextField.java). -For more details, see [built-in buttons](built_in_button.md#expand-a-field). - -![](expandable_1.png){width=332} - -If input data is secured, replace it with dots via [`JBPasswordField`](%gh-ic%/platform/platform-api/src/com/intellij/ui/components/JBPasswordField.java). - -![](password.png){width=271} - -If there are many predefined values (for example, code snippets, commit author), add completion to the input field [`TextFieldWithCompletion`](%gh-ic%/platform/platform-impl/src/com/intellij/util/textCompletion/TextFieldWithCompletion.java). - -![](input_field_completion.png){width=509} - -An input field with completion looks the same way as a regular input field. When an empty input field gets the focus, show a tooltip after a delay to indicate that code completion is supported. - -![](completion_tooltip.png){width=291} - -Show the completion popup when the user starts typing or presses Ctrl+Space. - -Use [built-in buttons](built_in_button.md) to help the user enter data. For example, to browse the disk. +![](input_focus_selection.png){width=706} ### Validation If the user enters an invalid value, highlight the field with red and show an error message in a tooltip. For more details, see [Validation errors](validation_errors.md). -![](input_field_error.png){width=239} +![](input_validation.png){width=706} ## Sizes and placement -Sizes are the same for all themes: - -![](input_field_sizes.png){width=65} - -### Field width +### Width Choose the width appropriate for the most common values, but not less than 65px. The field width helps the user understand what value is expected and to make sure that they fill the field correctly. -| Correct | ![](input_field_size_1.png){width=104} | -|-----------------------------------------------------|----------------------------------------| -| Incorrect | ![](input_field_size_2.png){width=240} | -| Correct | ![](input_field_size_3.png){width=387} | -| Incorrect | ![](input_field_size_4.png){width=331} | - -{style=none} - -If the input value is longer than the field width, show the beginning of the value when the field becomes inactive: - -![](size_long_name.png){width=243} - -### Placement + + + + + +
    CorrectIncorrect
    -If the input field depends on another control, for example, a checkbox, follow the rules for (layout.md#dependent-controls). Otherwise, follow the rules for [independent controls](layout.md#independent-controls). +If the input value is longer than the field width, show the beginning of the value when the field becomes inactive. - +Follow the [labeled input controls](layout.md#labeled-input-controls). diff --git a/topics/ui/controls/progress_bar.md b/topics/ui/controls/progress_bar.md index aec207351b1..4af37f1a723 100644 --- a/topics/ui/controls/progress_bar.md +++ b/topics/ui/controls/progress_bar.md @@ -12,7 +12,7 @@ A progress bar informs users about the progress of a lengthy operation. -![](determinate_example.png){width=308} +![](01 progress_bar.png){width=706} ## When to use @@ -21,112 +21,131 @@ Follow the rules for [progress indicators](progress_indicators.md). ## How to use ### Types +Use a determinate progress bar if the process duration is known. Otherwise, use **indeterminate** progress bar: -Use **determinate** progress bar, if the process duration is known: +![](02 determinate_and_ indeterminate.png){width=706} -![](determinate_example.png){width=308} +If an indeterminate process reaches a point where its duration can be determined, switch to a determinate progress bar: -Otherwise, use **indeterminate** progress bar: - -![](indeterminate_example.png){width=308} - -If an indeterminate process reaches a point where its duration can be determined, switch to a determinate progress bar. For example: - -![](progress_bar_indeterminate.png){width=308} - -![](progress_bar_determinate.png){width=308} +![](04 determinate_to_indeterminate.png){width=706} ### Process name and details -A progress bar can have a process name and process details. For wording, follow the rules for [progress text](progress_text.md). +A progress bar can have a process name and process details. #### Process name +Show the name of the operation being performed above the progress bar: -Place a process name above the progress bar: - -![](label_above.png){width=308} +![](05_process name.png){width=706} If the vertical space is limited, place the process name with a colon on the left: -![](progress_bar_label_left.png){width=308} - -If there are several processes in a group, add a bold header. The header is a noun. - -![](several_progresses.png){width=308} +![](07 process_name_on_the_left.png){width=706} -Do **not** show a process name for inline processes: +#### Process details +Show information about the current stage of an operation to make long-running tasks more predictable and manageable. -![](progress_bar_tool_window.png){width=605} +
    -#### Process details +Show details below the progress bar on a single line. The length of details is limited by the width of the progress bar. -Place process details under the progress bar in one line: +![](05_process details.png){width=706} -![](comment.png){width=308} +For wording, follow the rules for [progress text](progress_text.md). -The length of the comment is limited by the progress bar: +Examples: +* The current step: "Uploading file 3 of 10" +* The name of a file, module, or library: "Fetching guava-31.1.jar" +* Remaining time or percentage completed -![](comment_long.png){width=308} -If space is limited, show percentage completed: -![](horizontaly.png){width=342} +### Process controls -#### In dialog +Place process controls on the right next to the progress bar. On hover over the icon, show the name of the control under the progress bar instead of process details. -Use a process name as a dialog header, capitalize the title and remove ellipsis. Process details appear above the progress bar: +![](17 stop_button.png){width=706} -![](dialog.png){width=544} +#### Cancel or Stop button +Add a Cancel button if the process can be safely interrupted. If interrupting the process does not restore the system to its previous state, name the button Stop. -#### In status bar +![](17 cancel_button.png){width=706} -Place a process name under the progress bar in the Status bar: +#### Pause button -![](status_bar.png){width=238} +If the process takes a long time and can prevent the user from performing tasks, provide an option to pause a process. -### Process status +> It is recommended to run the process in the background so it doesn’t interrupt the user, instead of offering a pause option. +> +{style="note"} -If a process consists of substeps that can fail but do not terminate the process, then use green and red colors to show the intermediate status. -For example, show the status of the running tests: + + + + + + + + + + + + + +
    + Pause button + +

    Replace process details with the "Pause" comment on hover over the Pause icon.

    +
    + Process on pause + +

    If a user pauses the process, show "Paused" under the progress bar. Replace the Pause icon with Resume.

    +
    + Resume button + +

    Show "Resume" under the progress bar and when hovered over the Resume button.

    +
    -![](progress_color.png){width=390} +### Placement -Do **not** color progress bar to show the final result of the task, use [notifications](notification_types.md). -In case of success, show notification for the user-initiated tasks, in case of failure — for all tasks. +If you need to use the progress bar among other controls, place it close to the control that starts the process. -### Process control +![](23 placement.png){width=706} -Provide the Cancel button in the progress dialog if the process can be interrupted (see [Loading Project dialog](#in-dialog)). -Use the Stop button if interrupting does not return the environment to its previous state. +#### In dialog or popup -Use the Stop icon if there are several processes running at the same time in one dialog or there is not enough space for the button (e.g., [Status bar](#in-status-bar)): +> Place the progress bar in a modal dialog if the IDE cannot function properly until 
the process is completed. +> +{style="note"} -![](tasks_dialog.png){width=700} +Use a process name as a dialog or popup header, capitalize the title and remove the ellipsis.
Process details appear above the progress bar. +For a single progress bar, use a button to cancel or pause the process instead of an icon: -Always place the Stop icon on the right next to the progress bar. On hover over the Stop icon, show the "Stop" or "Cancel" comment under the progress bar instead of process details: +![](13 in_dialog.png){width=706} -![](hover_stop_icon.png){width=332} -If the process takes a long time and can prevent the user from performing tasks, provide an option to pause a process using the Pause button or the Pause icon. -Replace process details with the "Pause" comment on hover over the Pause icon: +For several processes in a group, add a common header and use icons for process controls: -![](pause.png){width=331} +![](16 process_control.png){width=706} -It is **not** recommended providing an option to pause the process. It is preferable that the process runs in the background and does not interfere with a user. +#### Inline progress -If a user pauses the process, show "Paused" under the progress bar. -Replace the Pause icon with Resume, show "Resume" under the progress bar and when hovered over the Resume button: +Use inline progress to indicate that content is being updated. The user can continue working with the content, but should see that a background process is in progress. -![](resume.png){width=330} +
    -Hide the progress bar as soon as the process completes. +Do not show a process name for an inline progress. -## Sizes and placement +![](09 inline_processes.png){width=706} -The progress form and sizes are the same in all themes. +#### Process status -![](progress_bar_sizes.png){width=586} +If a process consists of substeps that can fail but do not terminate the process, then use green and red colors to show the intermediate status. +For example, show the status of the running tests: +![](15 process_status.png){width=706} +#### Process complition +Hide the progress bar as soon as the process completes. diff --git a/topics/ui/controls/radio_button.md b/topics/ui/controls/radio_button.md index ad3aad4428c..a3f7bb4f954 100644 --- a/topics/ui/controls/radio_button.md +++ b/topics/ui/controls/radio_button.md @@ -18,49 +18,50 @@ Use a radio button group to choose one option from 2 to 4 mutually exclusive opt ## When not to use -### Several options in a group can be selected -Use a group of [checkboxes](checkbox.topic) instead. +### Several options can be selected +Use a group of [checkboxes](checkbox.topic) when several options can be selected. -### Binary Yes/No Options -For only two opposing yes/no options, use a checkbox instead. +### Yes or No Options +For only two opposing yes/no options, use a checkbox. - -
    - CorrectA correct example of using a checkbox instead of a radiobutton + + CorrectA correct example of using a checkbox instead of radiobuttons - IncorrectAn incorrect example of using a radiobutton instead of a checkbox + + IncorrectAn incorrect example of using radiobuttons instead of a checkbox
    -### 5 and more options -If the options have short labels, use a segmented button. Or, if the options can be represented on an axis, such as a time delay, use a slider instead. +### 2-5 options with short labels +If the options have short labels, use a segmented button. ![](03_When_to_use_Segmented_button.png){width=706} -For other cases with 5 or more options use a [drop-down list](drop_down.md): - +### When to use a drop-down instead +Consider using a [drop-down list](drop_down.md) if: +* There are more than 5 options: +
    - - -
    - CorrectA correct example of using a checkbox instead of a radiobutton + + CorrectA correct example of using a drop-down list instead of radiobuttons - IncorrectAn incorrect example of using a radiobutton instead of a checkbox + + IncorrectAn incorrect example of using radiobuttons for a list of 5 or more options
    + -### Use dropdown -Consider using a [drop-down list](drop_down.md) if: +* The options have long labels. * The screen space is limited. * The option might be used less often than other options on the screen. * There are other drop-down lists in the same group of UI components. A radio button group is more noticeable than a drop-down list, so it will look like a more important setting. -* There is a combination of several UI components for one setting: - ![](05_When_to_use_Segmented_button.png){width=706} - *The automatic updates setting consists of a checkbox, three lengthy-labeled options in a dropdown and a button.* +* The setting combines several UI components into one control: + +![](05_When_to_use_Segmented_button.png){width=706} ## How to use @@ -68,70 +69,73 @@ Consider using a [drop-down list](drop_down.md) if: - - + + - +
    Using links instead of buttons

    A label accompanies each checkbox and is placed next to it.

    Label example

    A label accompanies each radio button and is placed next to it.

    Using links instead of buttonsAn example of a label spanning two lines.

    If a label is long, split it into two lines. Avoid labels that take more than two lines. See recommendations on writing concise labels below.

    -To implement this, use HTML formatting: - - + + + -```kotlin -radioButton( - "Show options before adding
    to version control") -``` + ```kotlin + radioButton( + "Show options before adding
    to version control") + ``` -
    - + + -```java -new JRadioButton( - "Show options before adding
    to version control"); -``` + ```java + new JRadioButton( + "Show options before adding
    to version control"); + ``` -
    -
    +
    +
    + ### Writing guidelines -Use sentence-style capitalization. - -Do not use ending punctuation. +* Use sentence-style capitalization. +* Do not use ending punctuation. +* Use the imperative form of verbs. +* Do not use negation in labels as it complicates understanding. +* Make labels short and intelligible — see [Writing short and clear text](writing_short.md). -Use the imperative form of verbs. - -Do not use negation in labels as it complicates understanding. - - -
    - CorrectA correct example of using a checkbox instead of a radiobutton + + CorrectA correct example of using a drop-down list instead of radiobuttons - IncorrectAn incorrect example of using a radiobutton instead of a checkbox + + IncorrectAn incorrect example of using radiobuttons for a list of 5 or more options
    + -Make labels short and intelligible — see [Writing short and clear text](writing_short.md). ### Group label -![](09_How_to_use.png){width=706} - -Always start a radio button group with a group label. It explains what the options are for. + + + + + + + + + +
    Label example

    Always start a radio button group with a group label to explain what the options are for. Use a colon at the end of a group label.

    An example of a label spanning two lines.

    Use a checkbox or another radio button as a group label if the radio button group needs to be turned on or off.

    -Use a checkbox or another radio button as a group label if the radio button group needs to be turned on or off. -Use a colon at the end of a group label. ## Sizes and placement -If a radio button group depends on another control, e.g., a checkbox, follow the rules for [dependent colors](layout.md#dependent-controls). -Otherwise, follow the rules for [independent colors](layout.md). +Follow the layout of [checkboxes and radio-buttons](layout.md#checkboxes-and-radio-buttons) diff --git a/topics/ui/controls/split_icon_button.md b/topics/ui/controls/split_icon_button.md index 9d8ce1e144e..b0ce8cc6b78 100644 --- a/topics/ui/controls/split_icon_button.md +++ b/topics/ui/controls/split_icon_button.md @@ -10,50 +10,28 @@ -A split icon button appears on a horizontal toolbar and consists of two parts: the main icon and a triangle icon for the action list. +A split icon button appears on a horizontal [toolbar](toolbar.md) and consists of two parts: the main icon and a triangle icon for the action list. -![](split_icon_button_example.png){width=278} +![](split_icon_button.png){width=706} ## When to use -The split icon button helps reduce the number of icons on the toolbar and minimize visual noise. +Use the split icon button to reduce the number of actions on a horizontal toolbar if all the following conditions are met: +* There are already many controls on the toolbar. +* There is a group of similar actions. +* The user invokes one action more often than others. Or the user invokes one action several times, then switches to another action and invokes it several times but does not switch between actions too often. -Use the split icon button for a group of similar actions if there are already many icons on the toolbar and: - -* The user invokes one action more often than others, - -* Or if the user invokes one action several times, then switches to another action and invokes it several times but does not switch between actions too often. - -![](group_actions.png){width=325} - -*Profiler actions are grouped into a split button* - -If the user invokes actions with the same frequency or often switches from one action to another, use separate icons for each action. - -To decide whether to add the whole group of actions on the toolbar, follow the rules for the [toolbar](toolbar.md#what-items-to-add-on-toolbar). - -Use the split icon button on horizontal toolbars only, as it’s too wide for vertical toolbars. +To decide whether to add actions to the toolbar, follow the Toolbar guidelines. ## How to use -Make sure that all actions in the popup menu have icons. When an action is launched, its icon will be used as the main icon. - -![](behavior.png){width=325} - -*The user clicks Profile Allocations, the action starts, and its icon is shown as the main icon.* - -## Built-in behavior - -On hover, the main icon and the triangle icon are highlighted separately, and the line between two parts is added. -The tooltip for the main icon action is shown on hovering over it. - -![](split_icon_button_hover.png){width=192} - -The main icon invokes its action on click. The triangle icon opens the action menu on click: +### Add icons to all menu actions +Make sure that all actions in the drop-down menu have icons. When an action is selected, its icon will be shown on the toolbar. -![](click.png){width=325} +![](split_icon_button_main_action_icon.png){width=706} -If some actions are unavailable, the corresponding menu items are disabled. The action menu should always open, even if all the items in it are disabled. +### Disable unavailable actions +Do not hide the unavailable actions but show them as disabled to help users locate them in the future. The action menu should always open even if all the items in it are disabled. -![](split_icon_button_disabled.png){width=325} +![](split_icon_button_disabled_item.png){width=706} diff --git a/topics/ui/controls/tabs.md b/topics/ui/controls/tabs.md index f9ed4b7baea..3844b44e77f 100644 --- a/topics/ui/controls/tabs.md +++ b/topics/ui/controls/tabs.md @@ -10,63 +10,87 @@ -Tabs organize content in dialogs by grouping similar UI controls. -![](01_tabs_example.png){width=322} - -In code editors, tabs are created with another component — [`JBEditorTabs`](%gh-ic%/platform/platform-api/src/com/intellij/ui/tabs/impl/JBEditorTabs.kt). It supports extended functionality like icons, closeable, and draggable tabs. Do **not** use this component in dialogs. - -In tool windows, tabs are generated automatically. See also [Tool window](tool_window.md). +![Tabs](01_Tabs.png){width=706} ## When to use -Follow the rules in [Groups of controls](groups_of_controls.md). +Use tabs to organize related content. Follow rules for [Groups of controls](groups_of_controls.md). + +> For editor tabs, use another component — [`JBEditorTabs`](%gh-ic%/platform/platform-api/src/com/intellij/ui/tabs/impl/JBEditorTabs.kt) +> +>In tool windows, tabs are generated automatically. See [Tool window](tool_window.md). +> +{style="note"} ## How to use -Use title capitalization for tab labels. +### Label + +* Use title capitalization for tab labels. +* Make labels short, preferably no more than 3 words. +* Avoid generic words such as "General" or "Advanced". +* See [Writing short and clear](writing_short.md). + + +Correct + +![Hiding tabs that do not fit](02_How_to_use_correct.png){width=706} + +Incorrect + +![Hiding tabs that do not fit](02_How_to_use_incorrect.png){width=706} -Make the label short, preferably no more than 3 words. -Avoid generic words, such as "General" or "Advanced". -See [Writing short and clear](writing_short.md). -![](02_naming.png){width=284} +### Tab Order and Layout Place the most frequently used content in the first tab. -Tabs that do not fit allotted screen space automatically hide under the dropdown component. -(It is better to add no more than 8 tabs, but this number is not limited.) -![](03_hidden_tabs.png){width=533} +Tabs that do not fit allotted screen space automatically hide under the dropdown component. It is better to add no more than 8 tabs, but the number is not limited. -Always place tabs on top. It is possible to place them at other sides of the content — bottom, left, or right — but such a placement is extremely rare and might confuse users. +![Hiding tabs that do not fit](03_How_to_use.png){width=706} -Do not remove or disable a tab when its function is unavailable. Explain why a tab’s content is unavailable in the body of the tab. +### Unavailable content + +Do not remove or disable a tab when its functions are unavailable. Explain why a tab’s content is unavailable in the body of the tab. ## Placement -Make sure the border of the tab reaches the edges of the area tabs occupy. +### Position + +Always place tabs on top of the content. It is possible to place them at other sides — bottom, left, or right — but such a placement is extremely rare and might confuse users. -Incorrect -![](04_layout_border_incorrect.png){width=595} +### Independent content -Correct +Do not place independent content under the tabs. Create separate tabs for such content. -![](04_layout_border_correct.png){width=595} +Correct -Do **not** surround the tab content area with a visible border. +![Correct placment of independent content](06_Placement_correct.png){width=706} -Incorrect +Incorrect -![](05_bordered.png){width=595} +![Incorrect placement of independent content](06_Placement_incorrect.png){width=706} -Avoid placing independent content groups under the tabs' area. +### Controls above tabs +When there are other UI controls above tabs, separate them with a vertical indent. -Incorrect +![UI controls above the tabs](07_Placement_correct.png){width=706} -![](06_layout_content_under.png){width=595} +### Tabs border -When there are other UI controls above tabs, separate them with a vertical indent. +* Make sure the border of the tab reaches the edges of the area tabs occupy. +* Do **not** surround the tab content area with a visible border. + +Correct + +![Correct bottom border](04_Placement_correct.png){width=706} + +Incorrect + +![Incorrect bottom border](04_Placement_incorrect.png){width=706} -![](07_inset.png){width=595} +Incorrect +![Frame around the tab content](05_Placement_incorrect.png){width=706} diff --git a/topics/ui/controls/text_area.md b/topics/ui/controls/text_area.md index 877429d35c2..82c15779b54 100644 --- a/topics/ui/controls/text_area.md +++ b/topics/ui/controls/text_area.md @@ -21,7 +21,7 @@ Use a text area if input is unconstrained and long, or if the newline character Do **not** use a text area if: * Input consists of several words. Use an [input field](input_field.md) instead. -* There is not enough space for a text area, or if input is normally short but can occasionally be long or multi-line. Use an [expandable input field](input_field.md#input-field-types) instead. +* There is not enough space for a text area, or if input is normally short but can occasionally be long or multi-line. Use an [expandable input field](input_field.md#when-not-to-use) instead. * Values are added one by one. Use a [table](table.md) instead. * Text is read-only. Use a [description text](description_text.md) instead. diff --git a/topics/ui/controls/tooltip.md b/topics/ui/controls/tooltip.md index 58fd2bfa639..ffe9f1c8ef9 100644 --- a/topics/ui/controls/tooltip.md +++ b/topics/ui/controls/tooltip.md @@ -10,40 +10,46 @@ -A tooltip shows an action name or provides useful information about an action or a setting. +A tooltip appears on hovering over a UI element and shows an action name or provides useful information about an action or a setting. -![](01_top_pic.png){width=174} +Tooltip ## When to use There are three types of tooltips: - +
    - -
    - Action -

    Shows an action name or label for icons and unlabeled controls, and a shortcut if available.

    +
    + Action tooltip - + + Action +

    Shows an action name or label for icons and unlabeled controls such as main toolbar widgets, and a shortcut if available.

    +

    Required: action name

    +

    Optional: shortcut

    - Action help -

    Shows help text for icons and unlabeled controls in addition to an action name or label.

    + Action help tooltip
    - + Action help +

    Shows help text for icons and unlabeled controls in addition to an action name or label.

    +

    Required: action name, help text

    +

    Optional: shortcut, link

    - Help -

    Shows help text for all other controls.

    + Help tooltip
    - + Help +

    Shows help text for all other controls. It is shown on hovering the question mark icon.

    +

    Required: help text. Action name or label is not required because it is shown in the UI.

    +

    Optional: shortcut, link.

    @@ -55,132 +61,172 @@ Use **Action help** and **Help** tooltips according to the [Context help](contex ## How to use -### Required and optional information +[//]: # (### Required and optional information) -Always show the required information in a tooltip: +[//]: # () +[//]: # (Always show the required information in a tooltip:) - - - - - - - - - - - - - - - - - - - - -
    Tooltip Required info Optional
    -

    Action

    -

    -
    - Action name - - Shortcut -
    -

    Action help

    -

    -
    -

    Action name

    -

    Help text

    -
    -

    Shortcut

    -

    Link

    -
    -

    Help

    -

    -
    -

    Help text

    -

    No action name or label because it is already shown in the UI.

    -
    -

    Shortcut

    -

    Link

    -
    +[//]: # () +[//]: # () - +[//]: # (

    ) -Show a shortcut if an action or a setting has one. Do not show a single shortcut in a tooltip. +[//]: # ( ) -![](09_tooltip_only_incorrect.png){width=230} +[//]: # ( ) -Do not show just an action name and a link to a help article. Provide help text so that the user does not need to switch to a web browser. +[//]: # ( ) -The text width in an action tooltip is not limited. The text width in a help tooltip is limited by 250px. +[//]: # ( ) -Show no more than 10 lines of help text. If the text does not fit, leave only the essential information and add a link to a help article. +[//]: # ( ) -Incorrect +[//]: # ( ) -Text style formatting: +[//]: # ( ) - Correct +[//]: # ( ) -* Action name, shortcut and link do not allow HTML tagging. +[//]: # ( ) -If the help text is longer than 5 lines, separate the text into paragraphs with the `

    ` tag. The `

    ` tag adds vertical space between paragraphs to visually separate them. Do not use the `
    ` tag as it does not add space. +[//]: # (

    ) -![](12_tooltip_paragraph.png){width=300} +[//]: # ( ) + +[//]: # ( ) + +[//]: # ( ) + +[//]: # ( ) + +[//]: # (
    ) -Provide a link to a source that can further explain the action or the setting. A link can navigate to a place in the IDE or to an external help article. +[//]: # ( Action name) -| Local link | External link | -|---------------------------------------------|-------------------------------------------| -| ![](10_tooltip_local_link.png){width="300"} | ![](10_tooltip_ext_link.png){width="300"} | +[//]: # ( ) -![](11_link_only_incorrect.png){width=516} +[//]: # ( Shortcut) -### Text length and formatting +[//]: # (
    ) -![](tooltip_long_text_incorrect.png){width=601} +[//]: # (

    Action help

    ) -Correct +[//]: # (

    ) -![](tooltip_long_text_correct.png){width=601} +[//]: # (
    ) -* Avoid using style formatting in the help text. Usually, the text is short and no bold or italics are needed. +[//]: # (

    Action name

    ) - Incorrect +[//]: # (

    Help text

    ) - ![](tooltip_no_styling_incorrect.png){width=461} +[//]: # (
    ) - ![](tooltip_no_styling_correct.png){width=461} +[//]: # (

    Shortcut

    ) -* Use formatting for code, console commands or parameters. Use HTML tags. Enclosing the text in `` tags is not needed. +[//]: # (

    Link

    ) - ![](tooltip_code_styling.png){width=407 style=block} - *Editor breadcrumbs* +[//]: # (
    ) +[//]: # (

    Help

    ) + +[//]: # (

    ) + +[//]: # (
    ) + +[//]: # (

    Help text

    ) + +[//]: # (

    No action name or label because it is already shown in the UI.

    ) + +[//]: # (
    ) + +[//]: # (

    Shortcut

    ) + +[//]: # (

    Link

    ) + +[//]: # (
    ) + +### Shortcut +* Always show a shortcut if an action or a setting has one. +* Do not show a single shortcut in a tooltip: + + + + + + +
    + Correct + A tooltip with a shortcut + + Incorrect + A tooltip with a shortcut but without the action name
    + +### Link + +* Provide a link to a source that can further explain the action or the setting. A link can navigate to a place in the IDE or to an external help article: + + + + + + +
    + Internal link + A tooltip with an internal link + + External link + A tooltip with an external link +
    + +* Do not show just an action name and a link to a help article. Provide help text so that the user does not need to switch to a web browser: + + + + + + +
    + Correct + A tooltip with a link and help text + + Incorrect + A tooltip with a link but without help text
    + +### Text length + +The text width in an action tooltip is not limited. The text width in a help tooltip is limited by 250px. + +Show no more than 10 lines of help text. If the text does not fit, leave only the essential information and add a link to a help article. + + + + + + +
    + Correct + A tooltip with a long help text + + Incorrect + A tooltip with a too long help text
    + + +If the help text is longer than 5 lines, separate the text into paragraphs with the `

    ` tag. The `

    ` tag adds vertical space between paragraphs to visually separate them. Do not use the `
    ` tag as it does not add space. + @@ -207,14 +253,51 @@ new HelpTooltip().setDescription(LONG_TEXT).installOn(component); + + +### Text style formatting + +Avoid using style formatting in the help text. Usually, the text is short and no bold or italics are needed. + + + + + +
    + Correct + Text without formatting + + Incorrect + Text with formatting
    + +[//]: # () +[//]: # (* Use formatting for code, console commands or parameters. Use HTML tags. Enclosing the text in `` tags is not needed.) + +[//]: # () +[//]: # ( ![](tooltip_code_styling.png){width=407 style=block}) + +[//]: # ( *Editor breadcrumbs*) + +[//]: # () +[//]: # (* Action name, shortcut and link do not allow HTML tagging.) ### Writing guidelines -Make the help text [short and descriptive](writing_short.md). +* Make the help text [short and descriptive](writing_short.md). -In a help tooltip, do not repeat an action or a setting name in the text. +* In a help tooltip, do not repeat an action or a setting name in the text: -![](13_tooltip_dont_repeat_setting.png){width=394} + + + + + +
    + Correct + Text is not repeated + + Incorrect + Text repetition in the checkbox and the tooltip
    ### Question mark icon for help tooltips @@ -226,38 +309,50 @@ Examples with different controls: #### Checkbox -![](04_question_icon_tooltip.png){width=543} +Checkbox #### Tree item -![](05_question_icon_tree.png){width=390} +Tree item -#### Combo box +#### Labeled input + +Labeled input -![](14_placement_labeled_input.png){width=467} #### Group header -![](15_placement_group_header.png){width=409} +Group header + #### Settings breadcrumbs -![](16_placement_settings_header.png){width=458} +Settings breadcrumbs -#### Stand-alone button not at the bottom of a dialog +#### Button -![](07_help_tooltip_button.png){width=476} +Button -**Exception:** do not use the help tooltip with buttons at a dialog’s bottom. -Put the information into the help article that is opened with the question mark button in the bottom left corner. -Incorrect +**Exception**: do not use the help tooltip with buttons at a dialog’s bottom. +Put the information into the help article that is opened with the question mark button in the bottom left corner. -![](06_help_tooltip_button_incorrect.png){width=372} + + + + + +
    + Correct + Button in the dialog footer + + Incorrect + Button in the dialog footer with the incorrect help icon
    -## Style +[//]: # (## Style) -![](tooltip_style.png){width=723} +[//]: # () +[//]: # (![](tooltip_style.png){width=723}) ## Built-in behavior @@ -277,7 +372,7 @@ If the mouse cursor stays in the tooltip trigger area, tooltips are also hidden

    Hides after

    -

    If cursor is in the tooltip trigger area

    +

    If the cursor is in the tooltip trigger area

    diff --git a/topics/ui/principles/empty_state.md b/topics/ui/principles/empty_state.md index 1f4dee07d0f..59957e375ad 100644 --- a/topics/ui/principles/empty_state.md +++ b/topics/ui/principles/empty_state.md @@ -10,144 +10,279 @@ -Provide instructions in an empty UI area on how to fill it with data. Empty UI areas described here are: - -* [Tool window, list, tree or table](#tool-windows-lists-trees-and-tables) -* [Details area in a master-detail layout](#master-detail-layout) -* Empty search results — TBD - -## Tool windows, lists, trees and tables - -Instructional text for these UI areas consists of three parts: - -![](database-tw-callouts.png){width=626} - -### 1. Reason why empty - -Explain the current state. - -The default pattern is "_No [entity] added._" If _added, created, configured_ or other such verbs act as synonyms in a particular case, use the verb _added_ for consistency. - - - - - - - - - - +Empty states of tool windows, lists, trees, tables, master-detail layouts, or other container components should be informative for the users. +Fill in the empty states with the following: +- [A reason why the container is empty](#reason-why-empty) +- [Actions to fill in the area](#actions-to-fill-the-area) +- [A link to the corresponding help topic](#help-topic) + +Empty state of a tool window + +## Reason why empty + +### Explain the current state + +The default pattern is `No [entity] added.` If `added`, `created`, `configured`, or other words act as synonyms in a particular case, use `added` for consistency. + +
    Incorrect Correct
    Avoid "Nothing to show" as it is not informative.
    + + + +
    + Correct + Correct text in the empty state + + Incorrect + Incorrect text in the empty state +
    -Make the reason descriptive: - -Incorrect - -![](sql-dialect-before.png){width=456 style=block} -*The word mapping introduces a new entity while there are already two in the table header — path and SQL dialect. In the instructions, it is better to use already existing entities to connect them to what users see on the screen.* - -Correct - -![](sql-dialect-after.png){width=456 style=block} -*The word "individual" is used in contrast with the project SQL dialect above the table. The verb specified is used instead of added because, in the table, SQL dialects are not added but selected from a drop-down list in the SQL Dialect column.* - -### 2. Actions to fill the area +### Be precise + +

    Do not introduce new entities that are not used in the current context. +Instead, use the terms from the current UI so that the user understands +what exactly is missing:

    + + + + + + +
    + Correct + The reason is clear + + Incorrect + The reason is not clear
    -Required part. An action makes it easier to understand what to start with, instead of searching for the appropriate icon on the toolbar. It can also educate about the shortcut. +## Actions to fill the area -Use one or two actions. Three or more actions would make it harder to choose what to start from. +An action makes it easier to understand what to start with +instead of searching for the appropriate icon on the toolbar. +It can also educate about the shortcut. -![](maven-tw.png){width=300} +### Use one or two actions -If an action opens a menu, open it at the same position where it would be opened with the corresponding toolbar button. This would explain which toolbar icon opens the menu. +Three or more actions would make it harder to choose what to start from. -If an action cannot be tied to a link, explain what to do. + + + + + +
    + Correct + One action + + Incorrect + Three actions +
    -![](todo-tw.png){width=574} +In rare cases, when you need to list all possible starting points, use the list layout. -Hide the area's toolbar if it does not have the same action as in the empty state. Usually, all other toolbar actions are not relevant in this case. +If there is enough space (for example, in horizontal tool windows), you may use the table layout to place action links, shortcuts, and action descriptions: +Table layout for actions -Incorrect +### Open menus from the toolbar -![](todo-tw-toolbar-incorrect.png){width=574} +If an action opens a toolbar menu, open it at the same position where it +would be opened with the corresponding toolbar button. This would explain +which toolbar icon opens the menu. -### 3. Help topic + + + + + +
    + Correct + Toolbar menu + + Incorrect + Menu under the action +
    -**Tool windows:** provide a link to a help topic that explains the functionality. Add the question mark icon in the beginning. +### Explain what to do when there is no action` + +If there is no action that can be performed by clicking a link, +add a text describing all the required steps: + +Explain what to do when there is no action + +### Hide the toolbar + +Hide the area's toolbar if it does not have the same action as +in the empty state. Usually, all other toolbar actions are not +relevant in this case. + +Correct + +Hide the toolbar for the empty state + +Incorrect + +Toolbar is not needed + +## Help topic + + + + + + + + + +
    + Link to a help topic + + Link to a help topic +

    In tool windows and master-detail layouts, +provide a link to a help topic that explains the functionality. +Add the question mark icon in the beginning.

    +
    + Inline hint under the table + + Context help in inline hints +

    In tables, trees, and lists, provide instructions according to the inline text help rules. + Avoid using question mark links in these cases because such components rarely require deep explanations.

    +
    -![](empty_state_database-tw-segment.png){width=262} +## Empty state of the master-detail layout -**Tables, trees and lists:** provide instructions according to the [Context help](context_help.md) rules. Smaller UI areas rarely require an in-depth explanation compared to complex tool windows. A short help text should be enough, and it does not require switching contexts. +Master-detail layouts include a list or a tree on the left (in the master part) +and the details area on the right. -Incorrect +- If the master area is empty, display the explanation, action, and link to the help article. +- If the details area is empty, no explanations are needed. In this case, show the actions to fill in the area. -![](todo-filters-incorrect.png){width=456 style=block} -*Do not use a help topic link in a table and UI areas other than tool windows.* +Empty master-detail layout -Correct -![](todo-filters-correct.png){width=456 style=block} -*Place an inline help text under the table.* -### Writing guidelines +## Writing guidelines -See [Punctuation](punctuation.md) and [Capitalization](capitalization.md). +### Punctuation -Make the reason text short and descriptive. See [Writing short and clear](writing_short.md). +Separate sentences in the empty state with periods, but do not put a period after the action link. +Use the ellipses at the end of the action link if this link opens a dialog or a popup which requires some input from the user. + + + + + +
    + Correct + Correct punctuation in the empty state + + Incorrect + Incorrect punctuation in the empty state +
    -In actions, avoid words that describe physical actions like _press_ or _click_ — they are obvious from how the link works. +### Capitalization + +Use sentence capitalization in the empty state texts and links. + + + + + +
    + Correct + Correct capitalization in the empty state + + Incorrect + Incorrect capitalization in the empty state +
    -Avoid saying _add new_. Just use _add_ because all that is added is new in the context of an empty UI area. +### Avoid excessive verbs -## Master-detail layout +- In actions, avoid words that describe physical actions like `press` or `click` — they are obvious from how the link works. -Provide only the action part for the detail area in a master-detail layout. The detail area is filled when an item is selected in the master part. This behavior is obvious and does not need to be explained. +- Avoid saying `add new`. Just use `add` because all that is added is new in the context of an empty UI area. -The default pattern for the action is "_Select_ [entity] _to configure_". + + + + + +
    + Correct + Correct usage of verbs in the empty state + + Incorrect + Incorrect usage of verbs in the empty state +
    -The master area is usually a list or a tree, its empty state instructions should follow the guidelines for lists and trees. -![](app-servers.png){width=586} +## Sizes and placement -![](run-configs.png){width=720 style=block} -*The "Add Java application configuration" link is a shortcut to creating a new configuration instead of clicking the + button in the toolbar.* +[//]: # (The minimum text width is 40 characters. If an area is too narrow to show the minimum text width, show text in area fields, and if no fields are left, under the area borders.) -## Sizes and placement +[//]: # () +[//]: # (Incorrect) -The minimum text width is 40 characters. If an area is too narrow to show the minimum text width, show text in area fields, and if no fields are left, under the area borders. +[//]: # () +[//]: # (![](nbsp-incorrect.png){width=379}) -Use non-breaking spaces in an action name and shortcut, so it is not split into two lines. +[//]: # () +[//]: # (Correct) -Use non-breaking spaces for articles and prepositions in the instructional text. +[//]: # () +[//]: # (![](nbsp-correct.png){width=379}) -Incorrect +[//]: # () +[//]: # (The text is center-aligned. If possible, the center for the help topic link should be calculated with a 16px inset on the left. This helps visually align the help link with the lines above it.) -![](nbsp-incorrect.png){width=379} +[//]: # () +[//]: # (![](database-tw-markup1.png){width=300}) -Correct +Vertical spacing: -![](nbsp-correct.png){width=379} +Empty state vertical spacing -The text is center-aligned. If possible, the center for the help topic link should be calculated with a 16px inset on the left. This helps visually align the help link with the lines above it. +Minimum right and left margins: -![](database-tw-markup1.png){width=300} +Empty state horizontal spacing -Fields and vertical spaces: +Use non-breaking spaces in the following cases: +* Between action names and shortcuts +* For articles and prepositions + + + + + +
    + Correct + Correct usage of non-breaking spaces in the empty state + + Incorrect + Incorrect usage of non-breaking spaces in the empty state +
    -![](database-tw-markup2.png){width=530} +[//]: # (The text should wrap when a UI area’s width changes:) -The text should wrap when a UI area’s width changes: +[//]: # () +[//]: # (![](database-tw-horizontal.png){width=579}) -![](database-tw-horizontal.png){width=579} +[//]: # () +[//]: # (![](database-tw.png){width=300}) -![](database-tw.png){width=300} +[//]: # (## Style) -## Style +[//]: # () +[//]: # (The link should not be underlined.) -The link should not be underlined. +[//]: # () +[//]: # (In Darcula:) -In Darcula: +[//]: # () +[//]: # (![](database-tw-darcula.png){width=300}) -![](database-tw-darcula.png){width=300} +[//]: # () +[//]: # (Use non-breaking spaces for articles and prepositions in the instructional text.) +[//]: # () +[//]: # (Use non-breaking spaces for articles and prepositions in the instructional text.) diff --git a/topics/ui/text/punctuation.md b/topics/ui/text/punctuation.md index 555300b586a..a0da358b8f8 100644 --- a/topics/ui/text/punctuation.md +++ b/topics/ui/text/punctuation.md @@ -96,13 +96,15 @@ Between symbols in series. Use a colon after labels for inputs and radio button / checkbox groups. -![](label_noun.png){width=153} + -![](radio_example.png){width=213} +![](input_focus.png){width=706} + +![](checkbox_when_to_use.png){width=706} Do **not** use a colon if a label and text inside the input element make a phrase. -![](label_sentence.png){width=247} +![](input_placeholder_default.png){width=706} ## Contractions diff --git a/topics/ui/ui_guidelines_welcome.topic b/topics/ui/ui_guidelines_welcome.topic index 1a814a4119a..d6984171aa6 100644 --- a/topics/ui/ui_guidelines_welcome.topic +++ b/topics/ui/ui_guidelines_welcome.topic @@ -7,12 +7,12 @@ UI Guidelines - Refer to these guidelines to create consistent and usable interfaces for IntelliJ IDEs or plugins. + Create consistent and usable interfaces for IntelliJ IDEs or plugins. - + + User interface overview Components - Layout @@ -23,6 +23,7 @@ Colors Mnemonics Validation errors + Layout Resources diff --git a/topics/ui/ui_overview.md b/topics/ui/ui_overview.md new file mode 100644 index 00000000000..98cf3a150be --- /dev/null +++ b/topics/ui/ui_overview.md @@ -0,0 +1,213 @@ +# User interface overview +An introduction to IntelliJ IDE layout and core UI components + +By default, all IntelliJ-based IDEs use the following layout: + +Main Window + +The main application window of all IntelliJ-based IDEs by default includes the following parts: +* [Main toolbar](#main-toolbar) at the top +* [Stripes](#stripes) on the left and right sides that provide quick access to tool windows +* [Tool windows](#tool-windows) that surround the editor on the right, left, and bottom +* [Editor area](#editor-area) +* [Status bar](#status-bar) at the bottom + + +IntelliJ Platform also provides the following container elements: +* [Dialogs](#dialogs) +* [Popups](#popups) +* [Notifications](#notifications) +* [Context menus](#context-menus) + +See the full list of UI components in [](Components.topic). + +## Main toolbar +The main toolbar provides quick access to the most commonly used tools for managing the IDE and projects. +The main toolbar is fully [customizable](https://www.jetbrains.com/help/idea/customize-actions-menus-and-toolbars.html#customize-main-toolbar), +which means that the user may hide unnecessary widgets and buttons and add new ones. + +Main toolbar + +### Project widget +A drop-down control that allows opening existing projects or creating new ones: + +Project widget + +### VCS widget +A drop-down control for managing VCS branches: + +VCS widget + +### Run widget +A drop-down control for choosing run configurations and buttons for running and debugging the code: + +Run widget + +### Toolbar buttons +The icon buttons that provide quick access to Search, Settings, and other important IDE features. + +Main toolbar buttons + +### Main menu (on Windows and Linux) +On Windows and Linux, the toolbar also includes the Hamburger button: + +Main toolbar on Windows + +On clicking the Hamburger button, the menu items are shown on the right: + +Main menu expanded + +You can also opt for showing the menu above the toolbar: + +Main menu expanded on a separate line + + +## Tool windows +Tool windows are the panes inside the main application window that serve for solving different tasks, +for example, navigating through the project files in the Project tool window or working with Terminal in the +Terminal tool window: + +Terminal tool window + +See more in [Tool windows](tool_window.md). + +## Stripes + +The left and right sides of the main window feature vertical stripes containing tool window buttons. +These appear as icons by default but can be configured to display tool window names beneath them: + +Stripes + +See more in [Show and hide tool windows names](https://www.jetbrains.com/help/idea/tool-windows.html#show_or_hide_tool_window_names). + +## Editor area + +Editor area is the main working area in IntelliJ IDEs that is used to write, read, and modify code: + +Editor + +### Code editor + +The IntelliJ code editor provides highlighting, navigation, refactorings, and other powerful code insights features. +See implementation details in [Editor basics](editor_basics.md). + +### Editor tabs + +Tabs display the file name and extension. They can be [pinned](https://www.jetbrains.com/help/idea/using-code-editor.html#pin-or-unpin-a-tab), [opened in separate windows](https://www.jetbrains.com/help/idea/using-code-editor.html#detach_tab) or in a [split view](https://www.jetbrains.com/help/idea/using-code-editor.html#split_screen). + +Editor tabs + +See more details on working with tabs in the editor in [Editor tabs](https://www.jetbrains.com/help/idea/using-code-editor.html#manage_tabs). For UI component reference, go to [Tabs](tabs.md). + +### Inspection widget +A small control in the top-right corner of the editor shows the number of errors, warnings, and typos and allows navigating to the detailed view in the Project tool window. + +Inspection widget + +See more in [File and project analysis](https://www.jetbrains.com/help/idea/file-and-project-analysis.html#analysis-current-file). + +### Gutter +A vertical area along the left side of the editor that provides important information and action icons within easy reach. It shows line numbers and buttons for folding, navigating, and running and debugging code along with VCS stripes and other controls. + +Editor gutter + +See more in [Editor gutter](https://www.jetbrains.com/help/idea/editor-gutter.html). + +### Inlays + +Hints that show additional information like parameter types or variable values and interactive controls for showing annotations, usages, and more. + +Inlays + +See more in [implementation details](inlay_hints.md) and [user guidelines](https://www.jetbrains.com/help/idea/inlay-hints.html). + +### Floating toolbar +A small toolbar that appears when you select a code fragment in the editor. It contains buttons and controls for the most popular actions relevant in the current context, +such as quick fixes, AI-actions, basic refactorings, and code-formatting options: + +Floating toolbar + +See more in [Floating toolbar](https://www.jetbrains.com/help/idea/working-with-source-code.html#floating_toolbar). + +## Status bar + +The status bar on the bottom of the main window displays information on the current state of the project and the IDE as well as the path to the currently opened file: + +Status bar + +### Navigation bar +The left part of the status bar by default is occupied by the navigation bar that is a compact alternative for the Project tool window. +It shows a path to the selected file and allows you to go to other files and directories using this path: + +Navigation bar + +### Status bar widgets +The right part of the status bar contains status bar widgets which show statuses of various IDE and project settings and provide actions for changing these settings. +For example, the indent widget shows the number of spaces for code formatting in the current file and allows users to change this number: + +Status bar widget + +See more information on status bar widgets implementation in [Status Bar Widgets](status_bar_widgets.md). + +## Dialogs + +In the IntelliJ Platform, dialogs are modal windows that appear over the main application screen and require user actions to proceed. +The dialogs might be used for different purposes, such as setting up the IDE and projects, creating new instances, asking for confirmations, and so on. + +### Dialog examples + +Settings: + +Settings dialog + +Welcome screen: + +Welcome screen + +New project wizard: + +New project wizard + + +## Popups + +A popup is a lightweight window that appears above the application screen. Unlike the dialogs, popups do not have the standard OS +title bar and are usually dismissed by clicking outside. + +### Popup examples + +Completion popup: + +Completion popup + +Documentation popup: + +Documentation popup + + +## Notifications + +In IntelliJ Platform, different components are used to inform users about various events and status changes, depending on the severity and context of the message. + +### Balloons + +[Notification balloons](balloon.md) inform users on the events or system states related to a project or IDE: + +Notification balloon + +### Alerts + +Alerts are modal windows that draw the user's attention to crucial information or ask for confirmation before proceeding: + +Alert + +### Banners +[Banners](banner.md) appear on top of the editor or in tool windows. They inform the user about the state of a specific context and suggest context-related actions and quick fixes. + +Banner + +## Context menus + +Context menus list actions available in the current context and open on right-click: + +Context menu diff --git a/topics/user_interface_components/dialog_wrapper.md b/topics/user_interface_components/dialog_wrapper.md index 2440e5a6e05..4a74b4f478e 100644 --- a/topics/user_interface_components/dialog_wrapper.md +++ b/topics/user_interface_components/dialog_wrapper.md @@ -12,7 +12,7 @@ ## `DialogWrapper` -The [`DialogWrapper`](%gh-ic%/platform/platform-api/src/com/intellij/openapi/ui/DialogWrapper.java) is the base class which is supposed to be used for all modal dialogs (and some non-modal dialogs) shown in IntelliJ Platform. +The [`DialogWrapper`](%gh-ic%/platform/platform-api/src/com/intellij/openapi/ui/DialogWrapper.java) is the base class for all modal dialogs (and some non-modal dialogs) shown in IntelliJ Platform. It provides the following features: @@ -41,24 +41,31 @@ Optionally: * Override the `getPreferredFocusedComponent()` method and return the component that should be focused when the dialog is first displayed. * Override the `getDimensionServiceKey()` method to return the identifier which will be used for persisting the dialog dimensions. -* Override the `getHelpId()` method to return the context help topic associated with the dialog (see [Context Help](ide_infrastructure.md#context-help)). +* Override the `getHelpId()` method to return the context help topic associated with the dialog (see [](ide_infrastructure.md#context-help)). #### Dialog Content Use [Kotlin UI DSL](kotlin_ui_dsl_version_2.md) to provide the dialog's contents (see [samples](#kotlin)). Alternatively or when using Java, the `DialogWrapper` class can be used together with [GUI Designer forms](https://www.jetbrains.com/help/idea/gui-designer-basics.html). -In this case, bind a GUI Designer form to the class extending `DialogWrapper`, bind the top-level panel of the form to a field and return that field from the `createCenterPanel()` method. +In this case, bind a GUI Designer form to the class extending `DialogWrapper`, bind the top-level panel of the form to a field, and return that field from the `createCenterPanel()` method. -> See [](layout.md) topic in UI Guidelines for recommendations on arranging UI controls in dialogs. +> See the [](layout.md) topic in UI Guidelines for recommendations on arranging UI controls in dialogs. > > Existing dialogs can be inspected at runtime using [UI Inspector](internal_ui_inspector.md), for example, to locate the underlying implementation of UI components. > #### Displaying the Dialog -To display the dialog, call the `show()` method and then use the `getExitCode()` method to check how the dialog was closed (see `DialogWrapper#OK_EXIT_CODE, CANCEL_EXIT_CODE, CLOSE_EXIT_CODE`). +To display the dialog, call the `show()` method. + +To get the exit code of a modal dialog, use the `getExitCode()` method to check how the dialog was closed (see `DialogWrapper#OK_EXIT_CODE, CANCEL_EXIT_CODE, CLOSE_EXIT_CODE`). The `showAndGet()` method can be used to combine these two calls. +To execute some code after a non-modal dialog is closed, override the `doOKAction()`, `doCancelAction()`, or register a [disposable](disposers.md), for example: +```java +Disposer.register(dialog.getDisposable(), () -> action()); +``` + #### Customizing Buttons To customize the buttons displayed in the dialog (replacing the standard OK/Cancel/Help set of buttons), override either the `createActions()` or `createLeftActions()` methods. @@ -77,7 +84,7 @@ override the `doValidate()` method to perform the actual validation. The method will be called automatically via a timer. If the currently entered data is valid, return `null`. -Otherwise, return a [`ValidationInfo`](%gh-ic%/platform/ide-core/src/com/intellij/openapi/ui/ValidationInfo.java) object which encapsulates an error message, and an optional component associated with the invalid data. +Otherwise, return a [`ValidationInfo`](%gh-ic%/platform/ide-core/src/com/intellij/openapi/ui/ValidationInfo.java) object which encapsulates an error message and an optional component associated with the invalid data. When specifying a component, an error icon will be displayed next to it, and it will be focused when the user tries to invoke the OK action. ## Examples @@ -107,13 +114,13 @@ public class SampleDialogWrapper extends DialogWrapper { } ``` -Show `SampleDialogWrapper` dialog when user clicks on button: +Show the `SampleDialogWrapper` dialog when a user clicks a button: ```java JButton testButton = new JButton(); testButton.addActionListener(actionEvent -> { if (new SampleDialogWrapper().showAndGet()) { - // user pressed OK + // OK pressed } }); ``` diff --git a/topics/user_interface_components/kotlin_ui_dsl.md b/topics/user_interface_components/kotlin_ui_dsl.md index 997fda1e9b9..e70447e8313 100644 --- a/topics/user_interface_components/kotlin_ui_dsl.md +++ b/topics/user_interface_components/kotlin_ui_dsl.md @@ -1,4 +1,4 @@ - + # Kotlin UI DSL Version 1 @@ -11,9 +11,9 @@ -> When targeting IntelliJ Platform 2021.3 and later only use [](kotlin_ui_dsl_version_2.md). +> When targeting IntelliJ Platform 2021.3 and later, only use [Kotlin UI DSL Version 2](kotlin_ui_dsl_version_2.md) (currently called just _Kotlin UI DSL_). > -> **The version documented on this page is deprecated and will be removed in future platform releases.** +> **Usage of the version documented on this page is an error since 2025.1.** > > Please note [breaking changes](api_changes_list.md) can occur for this API between major releases. > @@ -329,3 +329,75 @@ Sample usages in IntelliJ Platform IDEs: ### One Cell Is Minimum, Second One Is Maximum Set `CCFlags.growX` and `CCFlags.pushX` for some component in the second cell. + +## Comparison with Kotlin UI DSL Version 2 + +> [_Kotlin UI DSL_](kotlin_ui_dsl_version_2.md) was formerly known as _Kotlin UI DSL **Version 2**_. +> +> _Kotlin UI DSL **Version 1**_ was deprecated starting from 2021.3, and its API was gradually reduced. +> Since 2025.1 its usage is considered an error. +> +> For simplicity, _Kotlin UI DSL **Version 2**_ is now just _Kotlin UI DSL_. + +The [new Kotlin UI DSL](kotlin_ui_dsl_version_2.md) fixes some crucial problems from version 1. +See [](#migration-to-version-2) on how to port existing UI DSL code from version 1 to the new version. + +The following significant changes were made: + +- Reduced API, which allows conceiving API easier and faster. + Example: there were five overloaded methods `Cell.checkBox()` in version 1, now only one method remains. + Functionality for binding properties is extracted into `Cell.bindSelected()` methods. +- UI DSL became stricter, so the available API in every context is much smaller. + Example: code like `row { row {` is forbidden now. +- Structured API is mostly based on interfaces because it's easier to learn API by grouped methods. + Only a small part of the API is implemented as extensions. +- KDoc is widely used. +- MIG layout is fully removed from the new UI DSL and replaced by `GridLayout`. + Because MIG layout is an external library, it's hard to fix bugs there (e.g., there are layout problems when components become invisible) and extend its functionality. + Fixed focus ring cropping problems: when components are placed near the panel border focus ring could be cropped if panel insets do not specify enough space. +- Implemented [Placeholder](kotlin_ui_dsl_version_2.md#placeholder) that allows replacing components at runtime after content is shown. + +### Migration to Version 2 + +The new API is very similar to the old one and covers almost all functionality now, so moving to the new version can be done quickly. + +Version 1 is placed in `com.intellij.ui.layout` package. + +Version 2 is placed in `com.intellij.ui.dsl.builder` package. + + + +1. Having a screenshot or live version of the initial components layout can help +2. Remove imports of old UI DSL starting with `com.intellij.ui.layout` +3. Go to the place where the panel is created and import the new UI DSL `com.intellij.ui.dsl.builder` suggested by IntelliJ IDEA +4. Update non-compilable code, according to the following table. + + + +| Version 1 | Version 2 | +|---------------------------------------------------|-----------------------------------------------------------------------| +| `row { row {` | `indent { row {` | +| `row { cell(isFullWidth = true)` | `row {` | +| `fullRow {` | `row {` | +| `titledRow(…) {` | `group(…) {` | +| `hideableRow` | `collapsibleGroup` | +| `cell` used as sub-grid | `row { panel { … } }` | +| `component(…)` or its invocation via `()` | `cell(…)` | +| `enableIf` | `enabledIf` | +| `checkBox(text, bindOptions)` | `checkBox(text).bindSelected(bindOptions)` | +| `radioButton(text, bindOptions)` | `radioButton(text).bindSelected(bindOptions)` | +| `comboBox(…, bindOptions)` | `comboBox(text).bindItem(bindOptions)` | +| `textField(bindOptions, columns)` | `textField().bindText(bindOptions).columns(columns)` | +| `scrollableTextArea(bindOptions, rows, columns)` | `textArea().bindText(bindOptions).rows(rows).columns(columns)` | +| `intTextField(bindOptions, columns, range, step)` | `intTextField(range, step).bindIntText(bindOptions).columns(columns)` | +| `textFieldWithBrowseButton(bindOptions, …)` | `textFieldWithBrowseButton(…).bindText(bindOptions)` | +| `.growPolicy(GrowPolicy.COLUMNS_SHORT)` | `.columns(SHORT_TEXT)` | +| `.growPolicy(GrowPolicy.MEDIUM_TEXT)` | `.columns(COLUMNS_MEDIUM)` | +| `label(…, bold = true)` | `label(…).bold()` | +| `withLeftGap()` | For previous left cell use `Cell.gap(SMALL)` | +| `withLeftGap(gapLeft)` | Please do not use custom gaps if possible | +| `withLargeLeftGap()` | Not needed, this gap is set by default | +| `withValidationOnInput` | `validationOnInput` | +| `withValidationOnApply` | `validationOnApply` | +| `withErrorOnApplyIf` | `errorOnApply` | +| `withBinding` | `bind` | diff --git a/topics/user_interface_components/kotlin_ui_dsl_version_2.md b/topics/user_interface_components/kotlin_ui_dsl_version_2.md index 372383938b6..8787387a158 100644 --- a/topics/user_interface_components/kotlin_ui_dsl_version_2.md +++ b/topics/user_interface_components/kotlin_ui_dsl_version_2.md @@ -1,6 +1,6 @@ - + -# Kotlin UI DSL Version 2 +# Kotlin UI DSL Kotlin DSL for creating UI forms with input components bound to a state object. @@ -11,19 +11,14 @@ -> This page describes API available in IntelliJ Platform releases **2021.3 and later** only. -> -> See [](kotlin_ui_dsl.md) for targeting earlier releases. -> - -Kotlin UI DSL Version 2 allows creating UI forms with input components bound to state objects. +Kotlin UI DSL allows creating UI forms with input components bound to state objects. The forms are built by using a declarative Kotlin syntax and follow the official IntelliJ Platform UI conventions described in the [](ui_guidelines_welcome.topic). The library is written in [Kotlin](using_kotlin.md) and makes it easy to develop user interfaces like [dialogs](dialog_wrapper.md) and [settings pages](settings.md). The Kotlin UI DSL is not intended to build general UIs, like [tool windows](tool_window.md) controls that trigger some actions and do not contain any input components bound to state objects. For this purpose, use [custom Swing components](user_interface_components.md) from the IntelliJ Platform or the standard ones. -The _Kotlin UI DSL Version 2_ functions are located in the [`com.intellij.ui.dsl.builder`](%gh-ic%/platform/platform-impl/src/com/intellij/ui/dsl/builder) package. +The _Kotlin UI DSL_ functions are located in the [`com.intellij.ui.dsl.builder`](%gh-ic%/platform/platform-impl/src/com/intellij/ui/dsl/builder) package. ## UI DSL Examples @@ -468,69 +463,3 @@ buttonsGroup(title = "radioButton:") { } }.bind(model::radioButtonColor) ``` - -## Version 1 and 2 Comparison - -In UI DSL version 2, some crucial problems from version 1 have been fixed, so porting is highly desirable. -See [](#migration-from-version-1) on how to port existing UI DSL code from version 1 to version 2 API. -Version 1 is deprecated and will be removed in future platform releases. - -The following significant changes were made: - -- Reduced API, which allows conceiving API easier and faster. - Example: there were 5 overloaded methods `Cell.checkBox()` in version 1, now only one method remains. - Functionality for binding properties is extracted into `Cell.bindSelected()` methods. -- UI DSL became stricter, so the available API in every context is much smaller. - Example: code like `row { row {` is forbidden now. -- Structured API is mostly based on interfaces, because it's easier to learn API by grouped methods. - Only a small part of the API is implemented as extensions. -- KDoc is widely used. -- MIG layout is fully removed from the new UI DSL and replaced by `GridLayout`. - Because MIG layout is an external library, it's hard to fix bugs there (e.g., there are layout problems when components become invisible) and extend its functionality. - Fixed focus ring cropping problems: when components are placed near the panel border focus ring could be cropped if panel insets do not specify enough space. -- Implemented [Placeholder](#placeholder) that allows replacing components at runtime after content is shown. - -### Migration from Version 1 - -The new API is very similar to the old one and covers almost all functionality now, so moving to the new version can be done quickly. - -Version 1 is placed in `com.intellij.ui.layout` package. - -Version 2 is placed in `com.intellij.ui.dsl.builder` package. - - - -1. Having a screenshot or live version of the initial components layout can help -2. Remove imports of old UI DSL starting with `com.intellij.ui.layout` -3. Go to the place where the panel is created and import new UI DSL `com.intellij.ui.dsl.builder` suggested by IntelliJ IDEA -4. Update non-compilable code, using the following table - - - -| Version 1 | Version 2 | -|---------------------------------------------------|-----------------------------------------------------------------------| -| `row { row {` | `indent { row {` | -| `row { cell(isFullWidth = true)` | `row {` | -| `fullRow {` | `row {` | -| `titledRow(…) {` | `group(…) {` | -| `hideableRow` | `collapsibleGroup` | -| `cell` used as sub-grid | `row { panel { … } }` | -| `component(…)` or its invocation via `()` | `cell(…)` | -| `enableIf` | `enabledIf` | -| `checkBox(text, bindOptions)` | `checkBox(text).bindSelected(bindOptions)` | -| `radioButton(text, bindOptions)` | `radioButton(text).bindSelected(bindOptions)` | -| `comboBox(…, bindOptions)` | `comboBox(text).bindItem(bindOptions)` | -| `textField(bindOptions, columns)` | `textField().bindText(bindOptions).columns(columns)` | -| `scrollableTextArea(bindOptions, rows, columns)` | `textArea().bindText(bindOptions).rows(rows).columns(columns)` | -| `intTextField(bindOptions, columns, range, step)` | `intTextField(range, step).bindIntText(bindOptions).columns(columns)` | -| `textFieldWithBrowseButton(bindOptions, …)` | `textFieldWithBrowseButton(…).bindText(bindOptions)` | -| `.growPolicy(GrowPolicy.COLUMNS_SHORT)` | `.columns(SHORT_TEXT)` | -| `.growPolicy(GrowPolicy.MEDIUM_TEXT)` | `.columns(COLUMNS_MEDIUM)` | -| `label(…, bold = true)` | `label(…).bold()` | -| `withLeftGap()` | For previous left cell use `Cell.gap(SMALL)` | -| `withLeftGap(gapLeft)` | Please do not use custom gaps if possible | -| `withLargeLeftGap()` | Not needed, this gap is set by default | -| `withValidationOnInput` | `validationOnInput` | -| `withValidationOnApply` | `validationOnApply` | -| `withErrorOnApplyIf` | `errorOnApply` | -| `withBinding` | `bind` | diff --git a/v-releases.list b/v-releases.list deleted file mode 100644 index 409cc43982b..00000000000 --- a/v-releases.list +++ /dev/null @@ -1,11 +0,0 @@ - - - - - - - - - - diff --git a/v.list b/v.list index 2433d7e1e1c..aa215d28f99 100644 --- a/v.list +++ b/v.list @@ -6,8 +6,8 @@ - - + + @@ -16,6 +16,7 @@ + @@ -27,16 +28,20 @@ - - + + + + - + + + diff --git a/writerside.cfg b/writerside.cfg index 0556676f6a5..eb2e962f37c 100644 --- a/writerside.cfg +++ b/writerside.cfg @@ -1,4 +1,6 @@ + + @@ -12,7 +14,6 @@ -