summaryrefslogtreecommitdiff
path: root/java/java-features-trainer/src/com/intellij/java/ift/lesson/run/JavaDebugLesson.kt
blob: 1be3fdf2d0ba9ae66a93d6ba898c18be63f7461c (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
// Copyright 2000-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
package com.intellij.java.ift.lesson.run

import com.intellij.debugger.JavaDebuggerBundle
import com.intellij.debugger.settings.DebuggerSettings
import com.intellij.icons.AllIcons
import com.intellij.java.ift.JavaLessonsBundle
import com.intellij.openapi.editor.LogicalPosition
import com.intellij.openapi.options.OptionsBundle
import com.intellij.xdebugger.XDebuggerBundle
import training.dsl.LessonContext
import training.dsl.TaskTestContext
import training.dsl.highlightButtonById
import training.dsl.restoreChangedSettingsInformer
import training.learn.lesson.general.run.CommonDebugLesson
import training.ui.LearningUiManager
import javax.swing.JEditorPane

class JavaDebugLesson : CommonDebugLesson("java.debug.workflow") {

  override val testScriptProperties = TaskTestContext.TestScriptProperties(duration = 60)

  private val demoClassName = JavaRunLessonsUtils.demoClassName
  override val configurationName: String = demoClassName
  override val sample = JavaRunLessonsUtils.demoSample
  override var logicalPosition: LogicalPosition = LogicalPosition(10, 6)

  override val confNameForWatches: String = "Application"
  override val quickEvaluationArgument = "Integer.parseInt"
  override val debuggingMethodName = "findAverage"
  override val methodForStepInto: String = "extractNumber"
  override val stepIntoDirectionToRight = true

  override fun LessonContext.applyProgramChangeTasks() {

    if (isHotSwapDisabled()) {
      task {
        val feature = stateCheck { !isHotSwapDisabled() }
        val callbackId = LearningUiManager.addCallback {
          feature.complete(true)
          DebuggerSettings.getInstance().RUN_HOTSWAP_AFTER_COMPILE = DebuggerSettings.RUN_HOTSWAP_ASK
        }
        showWarning(JavaLessonsBundle.message("java.debug.workflow.hotswap.disabled.warning",
                                              strong(OptionsBundle.message("configurable.group.build.settings.display.name")),
                                              strong(OptionsBundle.message("exportable.XDebuggerSettings.presentable.name")),
                                              strong(XDebuggerBundle.message("debugger.hotswap.display.name")),
                                              strong(JavaDebuggerBundle.message("label.debugger.hotswap.configurable.reload.classes")
                                                       .removeSuffix(":")),
                                              callbackId)) {
          isHotSwapDisabled()
        }
      }
    }

    highlightButtonById("CompileDirty")

    task("CompileDirty") {
      text(JavaLessonsBundle.message("java.debug.workflow.rebuild", action(it), icon(AllIcons.Actions.Compile)))
      if (isAlwaysHotSwap()) {
        triggerUI().component { ui: JEditorPane ->
          ui.text.contains(JavaDebuggerBundle.message("status.hot.swap.completed.stop"))
        }
      }
      else {
        stateCheck {
          inHotSwapDialog()
        }
      }
      proposeModificationRestore(afterFixText)
      test { actions(it) }
    }

    task {
      if (!isAlwaysHotSwap()) {
        text(JavaLessonsBundle.message("java.debug.workflow.confirm.hot.swap"))
      }
      else {
        text(JavaLessonsBundle.message("java.debug.workflow.no.confirmation"))
      }
      stateCheck {
        isAlwaysHotSwap() || !inHotSwapDialog()
      }
      proposeModificationRestore(afterFixText)
      test(waitEditorToBeReady = false) {
        dialog(JavaDebuggerBundle.message("hotswap.dialog.title.with.session", JavaRunLessonsUtils.demoClassName)) {
          button("Reload").click()
        }
      }
    }

    highlightButtonById("Debugger.PopFrame")

    actionTask("Debugger.PopFrame") {
      proposeModificationRestore(afterFixText)
      JavaLessonsBundle.message("java.debug.workflow.drop.frame", code("extractNumber"), code("extractNumber"),
                                icon(AllIcons.Actions.PopFrame), action(it))
    }
  }

  private fun runHotSwapAfterCompile() = DebuggerSettings.getInstance().RUN_HOTSWAP_AFTER_COMPILE
  private fun isHotSwapDisabled() = runHotSwapAfterCompile() == DebuggerSettings.RUN_HOTSWAP_NEVER
  private fun isAlwaysHotSwap() = runHotSwapAfterCompile() == DebuggerSettings.RUN_HOTSWAP_ALWAYS

  private fun inHotSwapDialog(): Boolean {
    return Thread.currentThread().stackTrace.any { traceElement ->
      traceElement.className.contains("HotSwapUIImpl")
    }
  }

  override fun LessonContext.restoreHotSwapStateInformer() {
    if (!isHotSwapDisabled()) return
    restoreChangedSettingsInformer {
      DebuggerSettings.getInstance().RUN_HOTSWAP_AFTER_COMPILE = DebuggerSettings.RUN_HOTSWAP_NEVER
    }
  }

  override val sampleFilePath: String = "src/$demoClassName.java"
}