[devkit] inject reference "Action ID" (IJPL-116495)

add injections: featuresTrainer & lessons

GitOrigin-RevId: 910155a2594afa977c55b306fad377b25c412436
This commit is contained in:
Yann Cébron
2025-01-14 16:06:04 +00:00
committed by intellij-monorepo-bot
parent 6f410378b6
commit 6d46b77f7e
17 changed files with 37 additions and 21 deletions
@@ -123,6 +123,7 @@ abstract class OnboardingTourLessonBase(id: String) : CommonLogicForOnboardingTo
openProjectViewTask = taskId
var projectDirExpanded = false
@Suppress("InjectedReferences", "UnresolvedPluginConfigReference") // todo IJPL-165055
text(JavaLessonsBundle.message("java.onboarding.project.view.description",
action("ActivateProjectToolWindow")))
text(JavaLessonsBundle.message("java.onboarding.balloon.project.view"),
@@ -208,6 +208,7 @@ object GitLessonsUtil {
fun TaskContext.showWarningIfGitWindowClosed(restoreTaskWhenResolved: Boolean = false) {
showWarningIfToolWindowClosed(ToolWindowId.VCS,
GitLessonsBundle.message("git.window.closed.warning",
@Suppress("UnresolvedPluginConfigReference", "InjectedReferences") // todo IJPL-165055
action("ActivateVersionControlToolWindow"), strong("Git")),
restoreTaskWhenResolved)
}
@@ -307,7 +308,8 @@ object GitLessonsUtil {
stateCheck {
ToolWindowManager.getInstance(project).getToolWindow(ToolWindowId.VCS)?.isVisible == true
}
test { actions("ActivateVersionControlToolWindow") }
test { @Suppress("InjectedReferences", "UnresolvedPluginConfigReference") actions("ActivateVersionControlToolWindow") } // todo IJPL-165055
}
fun TaskTestContext.clickChangeElement(partOfText: String) {
@@ -118,6 +118,7 @@ class GitAnnotateLesson : GitLesson("Git.Annotate", GitLessonsBundle.message("gi
var firstDiffSplitter: DiffSplitter? = null
task {
text(GitLessonsBundle.message("git.annotate.choose.show.diff", strong(showDiffText)))
@Suppress("UnresolvedPluginConfigReference", "InjectedReferences") // no Action ID available
trigger("com.intellij.openapi.vcs.actions.ShowDiffFromAnnotation")
restoreByUi(openFirstDiffTaskId, delayMillis = defaultRestoreDelay)
test { clickShowDiffAction() }
@@ -192,6 +192,7 @@ class GitCommitLesson : GitLesson("Git.Commit", GitLessonsBundle.message("git.co
highlightToolWindowStripe(ToolWindowId.VCS)
@Suppress("UnresolvedPluginConfigReference", "InjectedReferences") // todo IJPL-165055
task("ActivateVersionControlToolWindow") {
openGitWindow(GitLessonsBundle.message("git.commit.open.git.window", action(it),
icon(AllIcons.Toolwindows.ToolWindowChanges),
@@ -75,6 +75,7 @@ class GitFeatureBranchWorkflowLesson : GitLesson("Git.BasicWorkflow", GitLessons
override val lessonContent: LessonContext.() -> Unit = {
highlightToolWindowStripe(ToolWindowId.VCS)
@Suppress("UnresolvedPluginConfigReference", "InjectedReferences") // todo IJPL-165055
task("ActivateVersionControlToolWindow") {
val gitWindowName = GitBundle.message("git4idea.vcs.name")
text(GitLessonsBundle.message("git.feature.branch.introduction.1", strong(branchName),
@@ -57,6 +57,7 @@ class GitInteractiveRebaseLesson : GitLesson("Git.InteractiveRebase", GitLessons
override val lessonContent: LessonContext.() -> Unit = {
highlightToolWindowStripe(ToolWindowId.VCS)
@Suppress("UnresolvedPluginConfigReference", "InjectedReferences") // todo IJPL-165055
task("ActivateVersionControlToolWindow") {
openGitWindow(GitLessonsBundle.message("git.interactive.rebase.open.git.window", action(it),
strong(GitBundle.message("git4idea.vcs.name"))))
@@ -170,6 +171,7 @@ class GitInteractiveRebaseLesson : GitLesson("Git.InteractiveRebase", GitLessons
text(GitLessonsBundle.message("git.interactive.rebase.invoke.fixup", LessonUtil.rawKeyStroke(fixupShortcut),
strong(GitBundle.message("rebase.entry.action.name.fixup"))))
triggerAndBorderHighlight().component { ui: BasicOptionButtonUI.ArrowButton -> isInsideRebaseDialog(ui) }
@Suppress("UnresolvedPluginConfigReference", "InjectedReferences") // no Action ID available
trigger("git4idea.rebase.interactive.dialog.FixupAction")
test(waitEditorToBeReady = false) {
invokeActionViaShortcut("ALT F")
@@ -197,6 +199,7 @@ class GitInteractiveRebaseLesson : GitLesson("Git.InteractiveRebase", GitLessons
text(GitLessonsBundle.message("git.interactive.rebase.invoke.squash",
LessonUtil.rawKeyStroke(squashShortcut), strong(GitBundle.message("rebase.entry.action.name.squash"))))
triggerAndBorderHighlight().component { ui: BasicOptionButtonUI.MainButton -> isInsideRebaseDialog(ui) }
@Suppress("UnresolvedPluginConfigReference", "InjectedReferences") // no Action ID available
trigger("git4idea.rebase.interactive.dialog.SquashAction")
restoreState {
val table = previous.ui as? JBTable ?: return@restoreState false
@@ -48,6 +48,7 @@ class GitProjectHistoryLesson : GitLesson("Git.ProjectHistory", GitLessonsBundle
override val lessonContent: LessonContext.() -> Unit = {
highlightToolWindowStripe(ToolWindowId.VCS)
@Suppress("UnresolvedPluginConfigReference", "InjectedReferences") // todo IJPL-165055
task("ActivateVersionControlToolWindow") {
openGitWindow(GitLessonsBundle.message("git.project.history.open.git.window", action(it),
icon(AllIcons.Toolwindows.ToolWindowChanges),
@@ -4,6 +4,7 @@ package training.dsl
import com.intellij.icons.AllIcons
import com.intellij.openapi.actionSystem.ActionManager
import com.intellij.openapi.util.text.StringUtil
import org.intellij.lang.annotations.Language
import training.ui.LearningUiManager
import training.util.replaceSpacesWithNonBreakSpace
import training.util.surroundWithNonBreakSpaces
@@ -12,7 +13,7 @@ import javax.swing.Icon
/* Here can be defined common methods for any DSL level */
interface LearningDslBase {
/** Show shortcut for [actionId] inside lesson step message */
fun action(actionId: String): String {
fun action(@Language("devkit-action-id") actionId: String): String {
return "<action>$actionId</action>".surroundWithNonBreakSpaces()
}
@@ -33,7 +34,7 @@ interface LearningDslBase {
}
/** Show an icon from action widh [actionId] ID inside lesson step message */
fun actionIcon(actionId: String): String {
fun actionIcon(@Language("devkit-action-id") actionId: String): String {
val icon = ActionManager.getInstance().getAction(actionId)?.templatePresentation?.icon ?: AllIcons.Toolbar.Unknown
val index = LearningUiManager.getIconIndex(icon)
return "<icon_idx>$index</icon_idx>"
@@ -35,7 +35,7 @@ abstract class LessonContext : LearningDslBase {
}
/** Describe a simple task: just one action required */
fun actionTask(action: String, getText: TaskContext.(action: String) -> @Nls String) {
fun actionTask(@Language("devkit-action-id") action: String, getText: TaskContext.(action: String) -> @Nls String) {
task {
text(getText(action))
trigger(action)
@@ -49,7 +49,7 @@ abstract class LessonContext : LearningDslBase {
* Just shortcut to write action name once
* @see task
*/
fun task(action: String, taskContent: TaskContext.(action: String) -> Unit) = task {
fun task(@Language("devkit-action-id") action: String, taskContent: TaskContext.(action: String) -> Unit) = task {
taskContent(action)
}
@@ -241,7 +241,7 @@ object LessonUtil {
EditorModificationUtil.setReadOnlyHint(editor, LearnBundle.message("learn.task.read.only.hint"))
}
fun actionName(actionId: String): @NlsActions.ActionText String {
fun actionName(@Language("devkit-action-id") actionId: String): @NlsActions.ActionText String {
val name = getActionById(actionId).templatePresentation.text?.replace("...", "")
return "<strong>${name}</strong>"
}
@@ -477,7 +477,7 @@ fun LessonContext.highlightOldDebugActionsToolbar(highlightInside: Boolean = fal
}
fun TaskContext.highlightToolbarWithAction(place: String,
actionId: String,
@Language("devkit-action-id") actionId: String,
highlightInside: Boolean,
usePulsation: Boolean,
clearPreviousHighlights: Boolean = true) {
@@ -655,7 +655,7 @@ fun LessonContext.restoreChangedSettingsInformer(restoreSettings: () -> Unit) {
}
}
fun LessonContext.highlightButtonById(actionId: String,
fun LessonContext.highlightButtonById(@Language("devkit-action-id") actionId: String,
highlightInside: Boolean = true,
usePulsation: Boolean = true,
clearHighlights: Boolean = true,
@@ -99,24 +99,24 @@ abstract class TaskContext : LearningDslBase {
open fun runtimeText(@Nls callback: RuntimeTextContext.() -> String?) = Unit
/** Simply wait until an user perform particular action */
open fun trigger(actionId: String) = Unit
open fun trigger(@Language("devkit-action-id") actionId: String) = Unit
/** Simply wait until an user perform actions */
open fun trigger(checkId: (String) -> Boolean) = Unit
/** Trigger on actions start. Needs if you want to split long actions into several tasks. */
open fun triggerStart(actionId: String, checkState: TaskRuntimeContext.() -> Boolean = { true }) = Unit
open fun triggerStart(@Language("devkit-action-id") actionId: String, checkState: TaskRuntimeContext.() -> Boolean = { true }) = Unit
/** [actionIds] these actions required for the current task */
open fun triggers(vararg actionIds: String) = Unit
open fun triggers(@Language("devkit-action-id") vararg actionIds: String) = Unit
/** An user need to rice an action which leads to necessary state change */
open fun <T : Any?> trigger(actionId: String,
open fun <T : Any?> trigger(@Language("devkit-action-id") actionId: String,
calculateState: TaskRuntimeContext.() -> T,
checkState: TaskRuntimeContext.(T, T) -> Boolean) = Unit
/** An user need to rice an action which leads to appropriate end state */
fun trigger(actionId: String, checkState: TaskRuntimeContext.() -> Boolean) {
fun trigger(@Language("devkit-action-id") actionId: String, checkState: TaskRuntimeContext.() -> Boolean) {
trigger(actionId, { }, { _, _ -> checkState() })
}
@@ -21,6 +21,7 @@ import org.assertj.swing.fixture.*
import org.assertj.swing.timing.Condition
import org.assertj.swing.timing.Pause
import org.assertj.swing.timing.Timeout
import org.intellij.lang.annotations.Language
import training.ui.IftTestContainerFixture
import training.ui.LearningUiHighlightingManager
import training.ui.LearningUiUtil
@@ -85,7 +86,7 @@ class TaskTestContext(rt: TaskRuntimeContext) : TaskRuntimeContext(rt) {
Pause.pause(300, TimeUnit.MILLISECONDS)
}
fun actions(vararg actionIds: String) {
fun actions(@Language("devkit-action-id") vararg actionIds: String) {
for (actionId in actionIds) {
val action = getActionById(actionId)
invokeActionForFocusContext(action)
@@ -51,6 +51,7 @@ abstract class FileStructureLesson
// There is no Structure tool window in the PyCharm Edu. So added this check.
@Suppress("UnresolvedPluginConfigReference") // todo IJPL-165055
if (ActionManager.getInstance().getAction("ActivateStructureToolWindow") != null) {
@Suppress("UnresolvedPluginConfigReference", "InjectedReferences") // todo IJPL-165055
task("ActivateStructureToolWindow") {
text(LessonsBundle.message("file.structure.toolwindow", action(it)))
stateCheck { focusOwner?.javaClass?.name.isToStringContains("StructureViewComponent") }
@@ -19,6 +19,7 @@ import org.assertj.swing.core.MouseClickInfo
import org.assertj.swing.data.TableCell
import org.assertj.swing.fixture.JTableFixture
import org.assertj.swing.fixture.JTextComponentFixture
import org.intellij.lang.annotations.Language
import training.dsl.*
import training.learn.LessonsBundle
import training.learn.course.KLesson
@@ -248,7 +249,7 @@ open class FindInFilesLesson(override val sampleFilePath: String,
}
private fun TaskContext.showWarningIfPopupClosed(isReplacePopup: Boolean) {
val actionId = if (isReplacePopup) "ReplaceInPath" else "FindInPath"
@Language("devkit-action-id") val actionId = if (isReplacePopup) "ReplaceInPath" else "FindInPath"
showWarning(LessonsBundle.message("find.in.files.popup.closed.warning.message", action(actionId), LessonUtil.actionName(actionId))) {
getFindPopup()?.helper?.isReplaceState != isReplacePopup
}
@@ -28,6 +28,7 @@ import com.intellij.xdebugger.impl.ui.XDebuggerEmbeddedComboBox
import com.intellij.xdebugger.impl.ui.tree.XDebuggerTree
import com.intellij.xdebugger.impl.ui.tree.nodes.WatchNodeImpl
import org.assertj.swing.fixture.JComboBoxFixture
import org.intellij.lang.annotations.Language
import org.jetbrains.annotations.Nls
import training.dsl.*
import training.dsl.LessonUtil.checkExpectedStateOfEditor
@@ -454,7 +455,7 @@ fun LessonContext.clearBreakpoints() {
}
}
fun LessonContext.runSample(actionId: String, @Nls message: String) {
fun LessonContext.runSample(@Language("devkit-action-id") actionId: String, @Nls message: String) {
task {
text(message, LearningBalloonConfig(Balloon.Position.below, 0, duplicateMessage = true))
checkToolWindowState(actionId, true)
@@ -7,7 +7,6 @@ import com.intellij.icons.AllIcons
import com.intellij.ide.DataManager
import com.intellij.ide.plugins.PluginManager
import com.intellij.ide.util.PropertiesComponent
import com.intellij.lang.Language
import com.intellij.notification.NotificationGroup
import com.intellij.notification.NotificationGroupManager
import com.intellij.openapi.actionSystem.ActionManager
@@ -33,6 +32,7 @@ import com.intellij.ui.ExperimentalUI
import com.intellij.ui.components.labels.LinkLabel
import com.intellij.util.PlatformUtils
import com.intellij.util.ui.JBUI
import org.intellij.lang.annotations.Language
import org.jetbrains.annotations.Nls
import training.lang.LangManager
import training.lang.LangSupport
@@ -68,14 +68,14 @@ internal fun courseCanBeUsed(languageId: String): Boolean {
return excludedCourses == null || !excludedCourses.contains(languageId)
}
internal fun findLanguageByID(id: String): Language? {
internal fun findLanguageByID(id: String): com.intellij.lang.Language? {
val effectiveId = if (id.equals("cpp", ignoreCase = true)) {
"ObjectiveC"
}
else {
id
}
return Language.findLanguageByID(effectiveId)
return com.intellij.lang.Language.findLanguageByID(effectiveId)
}
internal fun createBalloon(@Nls text: String): Balloon = createBalloon(text, 3000)
@@ -160,7 +160,7 @@ fun invokeActionForFocusContext(action: AnAction) {
}
}
fun getCallBackActionId(actionId: String): String {
fun getCallBackActionId(@Language("devkit-action-id") actionId: String): String {
val action = getActionById(actionId)
return LearningUiManager.addCallback { invokeActionForFocusContext(action) }
}
@@ -250,7 +250,7 @@ fun Any?.isToStringContains(string: String): Boolean {
return this.toNullableString()?.contains(string) ?: false
}
fun getActionById(actionId: String): AnAction {
fun getActionById(@Language("devkit-action-id") actionId: String): AnAction {
return ActionManager.getInstance().getAction(actionId)
?: error("No action with id $actionId in ${ApplicationNamesInfo.getInstance().fullProductNameWithEdition}")
}
@@ -359,6 +359,7 @@ class PythonOnboardingTourLesson :
var collapsed = false
text(PythonLessonsBundle.message("python.onboarding.project.view.description",
@Suppress("UnresolvedPluginConfigReference", "InjectedReferences") // todo IJPL-165055
action("ActivateProjectToolWindow")))
text(PythonLessonsBundle.message("python.onboarding.balloon.project.view"),
LearningBalloonConfig(Balloon.Position.atRight, width = 0, cornerToPointerDistance = 8))