mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
[IFT] Add Find and Replace in files lesson for java, python and ruby
IDEA-CR-69975 GitOrigin-RevId: 0db188d67ae1a5c294047e7e4eb95fe01d5f5e85
This commit is contained in:
committed by
intellij-monorepo-bot
parent
59013f4bda
commit
76db4f66dc
+5
@@ -0,0 +1,5 @@
|
||||
package util;
|
||||
|
||||
public final class Utils {
|
||||
public static final String[] FRUITS = new String[]{"pineapple", "banana", "apple", "grapes", "mango", "melon", "peach", "orange"};
|
||||
}
|
||||
+18
@@ -0,0 +1,18 @@
|
||||
package warehouse;
|
||||
|
||||
public final class FindInFilesSample {
|
||||
public static void main(String[] args) {
|
||||
Warehouse warehouse = new Warehouse();
|
||||
warehouse.addFruits("peach", 3);
|
||||
warehouse.addFruits("pineapple", 5);
|
||||
warehouse.addFruits("mango", 1);
|
||||
warehouse.addFruits("apple", 5);
|
||||
|
||||
boolean result = warehouse.takeFruit("apple");
|
||||
if (result) {
|
||||
System.out.println("This apple was delicious!");
|
||||
}
|
||||
|
||||
warehouse.printAllFruits();
|
||||
}
|
||||
}
|
||||
+49
@@ -0,0 +1,49 @@
|
||||
package warehouse;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import util.Utils;
|
||||
|
||||
public final class Warehouse {
|
||||
// Fruit name to amount of it in warehouse
|
||||
private final Map<String, Integer> entry = new HashMap<>(); // Apple, banana, etc...
|
||||
|
||||
public Warehouse() {
|
||||
String[] availableFruits = Utils.FRUITS;
|
||||
for (String fruit : availableFruits) {
|
||||
entry.put(fruit, 0);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param fruitName some fruit name from Utils.FRUITS (mango, apple...)
|
||||
*/
|
||||
public void addFruits(String fruitName, int quantity) {
|
||||
Integer curQuantity = entry.get(fruitName);
|
||||
if (curQuantity != null) {
|
||||
entry.put(fruitName, curQuantity + quantity);
|
||||
}
|
||||
else {
|
||||
throw new IllegalArgumentException("Not found fruit with name: " + fruitName);
|
||||
}
|
||||
}
|
||||
|
||||
public boolean takeFruit(String fruitName) {
|
||||
Integer curQuantity = entry.get(fruitName);
|
||||
if (curQuantity == null) {
|
||||
throw new IllegalArgumentException("Not found fruit with name: " + fruitName);
|
||||
}
|
||||
else if (curQuantity > 0) {
|
||||
entry.put(fruitName, curQuantity - 1);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public void printAllFruits() {
|
||||
for (Map.Entry<String, Integer> pair : entry.entrySet()) {
|
||||
System.out.println(pair.getKey() + ": " + pair.getValue());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -21,6 +21,7 @@ import training.learn.lesson.general.*
|
||||
import training.learn.lesson.general.assistance.CodeFormatLesson
|
||||
import training.learn.lesson.general.assistance.ParameterInfoLesson
|
||||
import training.learn.lesson.general.assistance.QuickPopupsLesson
|
||||
import training.learn.lesson.general.navigation.FindInFilesLesson
|
||||
import training.learn.lesson.general.refactorings.ExtractVariableFromBubbleLesson
|
||||
import training.learn.lesson.kimpl.LessonUtil
|
||||
|
||||
@@ -100,6 +101,7 @@ class JavaLearningCourse : LearningCourseBase(JavaLanguage.INSTANCE.id) {
|
||||
JavaInheritanceHierarchyLesson(it),
|
||||
JavaRecentFilesLesson(it),
|
||||
JavaOccurrencesLesson(it),
|
||||
FindInFilesLesson(it, lang, "src/warehouse/FindInFilesSample.java")
|
||||
)
|
||||
},
|
||||
LearningModule(name = LessonsBundle.message("run.debug.module.name"),
|
||||
|
||||
@@ -247,6 +247,23 @@ search.everywhere.finish=<strong>Done!</strong> Similarly, you can use {0} to lo
|
||||
to look for a file.
|
||||
search.everywhere.navigation.promotion=You will find other navigation actions and workflow use cases in the {0} module.
|
||||
|
||||
find.in.files.lesson.name=Find and replace in files
|
||||
find.in.files.show.find.popup=Suppose you want to find all occurrences of some string in the project. Press {0} to open the {1} window.
|
||||
find.in.files.type.to.find=Let''s type {0} to look for all textual occurrences in the Learning project.
|
||||
find.in.files.whole.words=You were supposed to find the <code>apple</code> string but also got some <code>pineapple</code> entries. \
|
||||
Let''s narrow down the search to a whole word. Click on {0} or press {1}.
|
||||
find.in.files.select.row=You can see the context of the found string in the embedded editor. \
|
||||
Click the highlighted row or navigate to it by {0} and {1} buttons.
|
||||
find.in.files.go.to.file=Also, you can open the selected file in the main editor. Press {0} or double click the row to move to this file.
|
||||
find.in.files.show.replace.popup=Suppose you want to replace all found occurrences with other string. \
|
||||
It may be very boring to perform replacing in each file consistently. <ide/> will help you with this task. Press {0} to open {1} window.
|
||||
find.in.files.type.to.replace=Let''s replace all occurrences of {0} with {1}. Type {1} in the highlighted field.
|
||||
find.in.files.select.directory=Also you can search or replace in the specified scope. \
|
||||
Click on the {0} button or press {1} to narrow the replacement only to current directory.
|
||||
find.in.files.press.replace.all=Press {0} to start refactoring.
|
||||
find.in.files.confirm.replace=And now press {0} to confirm refactoring.
|
||||
find.in.files.popup.closed.warning.message=Press {0} to open the {1} window again.
|
||||
|
||||
extract.method.lesson.name=Extract method
|
||||
extract.method.invoke.action=Press {0} to extract the selected code block into a method.
|
||||
extract.method.start.refactoring=Click {0} to start refactoring.
|
||||
|
||||
+231
@@ -0,0 +1,231 @@
|
||||
// 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 training.learn.lesson.general.navigation
|
||||
|
||||
import com.intellij.find.FindBundle
|
||||
import com.intellij.find.FindInProjectSettings
|
||||
import com.intellij.find.FindManager
|
||||
import com.intellij.find.SearchTextArea
|
||||
import com.intellij.find.impl.FindInProjectSettingsBase
|
||||
import com.intellij.find.impl.FindPopupPanel
|
||||
import com.intellij.icons.AllIcons
|
||||
import com.intellij.openapi.actionSystem.impl.ActionButton
|
||||
import com.intellij.testGuiFramework.fixtures.extended.ExtendedTableFixture
|
||||
import com.intellij.testGuiFramework.framework.GuiTestUtil
|
||||
import com.intellij.testGuiFramework.impl.actionButton
|
||||
import com.intellij.testGuiFramework.impl.button
|
||||
import com.intellij.testGuiFramework.impl.findComponentWithTimeout
|
||||
import com.intellij.testGuiFramework.util.Key
|
||||
import com.intellij.usages.UsagePresentation
|
||||
import com.intellij.util.ui.UIUtil
|
||||
import org.fest.swing.core.MouseClickInfo
|
||||
import org.fest.swing.data.TableCell
|
||||
import org.fest.swing.fixture.JTextComponentFixture
|
||||
import training.commands.kotlin.TaskContext
|
||||
import training.commands.kotlin.TaskRuntimeContext
|
||||
import training.commands.kotlin.TaskTestContext
|
||||
import training.learn.LessonsBundle
|
||||
import training.learn.interfaces.Module
|
||||
import training.learn.lesson.kimpl.*
|
||||
import java.awt.event.InputEvent
|
||||
import java.awt.event.KeyEvent
|
||||
import javax.swing.*
|
||||
|
||||
class FindInFilesLesson(module: Module, lang: String, override val existedFile: String)
|
||||
: KLesson("Find in files", LessonsBundle.message("find.in.files.lesson.name"), module, lang) {
|
||||
|
||||
override val lessonContent: LessonContext.() -> Unit = {
|
||||
resetFindSettings()
|
||||
|
||||
lateinit var showPopupTaskId: TaskContext.TaskId
|
||||
task("FindInPath") {
|
||||
showPopupTaskId = taskId
|
||||
text(LessonsBundle.message("find.in.files.show.find.popup",
|
||||
action(it), LessonUtil.actionName(it)))
|
||||
triggerByUiComponentAndHighlight(false, false) { popup: FindPopupPanel ->
|
||||
!popup.helper.isReplaceState
|
||||
}
|
||||
test {
|
||||
Thread.sleep(300)
|
||||
actions(it)
|
||||
}
|
||||
}
|
||||
|
||||
task("apple") {
|
||||
text(LessonsBundle.message("find.in.files.type.to.find", code(it)))
|
||||
stateCheck { getFindPopup()?.stringToFind?.toLowerCase() == it }
|
||||
restoreByUi()
|
||||
test { type(it) }
|
||||
}
|
||||
|
||||
task {
|
||||
val wholeWordsButtonText = FindBundle.message("find.whole.words").dropMnemonic()
|
||||
text(LessonsBundle.message("find.in.files.whole.words",
|
||||
icon(AllIcons.Actions.Words),
|
||||
LessonUtil.rawKeyStroke(KeyStroke.getKeyStroke(KeyEvent.VK_W, InputEvent.ALT_DOWN_MASK))))
|
||||
highlightAndTriggerWhenButtonSelected(wholeWordsButtonText)
|
||||
showWarningIfPopupClosed(false)
|
||||
test {
|
||||
ideFrame {
|
||||
actionButton(wholeWordsButtonText).click()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
task("apple...") {
|
||||
text(LessonsBundle.message("find.in.files.select.row",
|
||||
action("EditorUp"), action("EditorDown")))
|
||||
triggerByPartOfComponent { table: JTable ->
|
||||
val rowIndex = table.findLastRowIndexOfItemWithText(it)
|
||||
if (rowIndex >= 0) {
|
||||
table.getCellRect(rowIndex, 0, false)
|
||||
}
|
||||
else null
|
||||
}
|
||||
triggerByUiComponentAndHighlight(false, false) { table: JTable ->
|
||||
table.selectedRow != -1 && table.selectedRow == table.findLastRowIndexOfItemWithText(it)
|
||||
}
|
||||
restoreByUi(restoreId = showPopupTaskId)
|
||||
test {
|
||||
ideFrame {
|
||||
Thread.sleep(300)
|
||||
val table = findComponentWithTimeout { table: JTable -> table.findLastRowIndexOfItemWithText(it) != -1 }
|
||||
val tableFixture = ExtendedTableFixture(robot(), table)
|
||||
val rowIndex = table.findLastRowIndexOfItemWithText(it)
|
||||
tableFixture.click(TableCell.row(rowIndex).column(0), MouseClickInfo.leftButton())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
task {
|
||||
text(LessonsBundle.message("find.in.files.go.to.file", LessonUtil.rawEnter()))
|
||||
stateCheck { virtualFile.name != existedFile.substringAfterLast('/') }
|
||||
restoreByUi(restoreId = showPopupTaskId)
|
||||
test { GuiTestUtil.shortcut(Key.ENTER) }
|
||||
}
|
||||
|
||||
task("ReplaceInPath") {
|
||||
text(LessonsBundle.message("find.in.files.show.replace.popup",
|
||||
action(it), LessonUtil.actionName(it)))
|
||||
triggerByUiComponentAndHighlight(false, false) { popup: FindPopupPanel ->
|
||||
popup.helper.isReplaceState
|
||||
}
|
||||
test { actions(it) }
|
||||
}
|
||||
|
||||
task("orange") {
|
||||
text(LessonsBundle.message("find.in.files.type.to.replace",
|
||||
code("apple"), code(it)))
|
||||
triggerByUiComponentAndHighlight(highlightInside = false) { ui: SearchTextArea ->
|
||||
it.startsWith(ui.textArea.text)
|
||||
}
|
||||
stateCheck {
|
||||
getFindPopup()?.helper?.model?.let { model ->
|
||||
model.stringToReplace == it && model.stringToFind == "apple"
|
||||
} ?: false
|
||||
}
|
||||
restoreByUi()
|
||||
test {
|
||||
ideFrame {
|
||||
val textArea = findComponentWithTimeout { textArea: JTextArea -> textArea.text == "" }
|
||||
JTextComponentFixture(robot(), textArea).click()
|
||||
type(it)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
task {
|
||||
val directoryScopeText = FindBundle.message("find.popup.scope.directory").dropMnemonic()
|
||||
text(LessonsBundle.message("find.in.files.select.directory",
|
||||
strong(directoryScopeText),
|
||||
LessonUtil.rawKeyStroke(KeyStroke.getKeyStroke(KeyEvent.VK_D, InputEvent.ALT_DOWN_MASK))))
|
||||
highlightAndTriggerWhenButtonSelected(directoryScopeText)
|
||||
showWarningIfPopupClosed(true)
|
||||
test {
|
||||
ideFrame {
|
||||
actionButton(directoryScopeText).click()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
val replaceAllDialogTitle = FindBundle.message("find.replace.all.confirmation.title")
|
||||
task {
|
||||
val replaceAllButtonText = FindBundle.message("find.popup.replace.all.button").dropMnemonic()
|
||||
text(LessonsBundle.message("find.in.files.press.replace.all", strong(replaceAllButtonText)))
|
||||
triggerByUiComponentAndHighlight { button: JButton ->
|
||||
button.text == replaceAllButtonText
|
||||
}
|
||||
triggerByUiComponentAndHighlight(false, false) { dialog: JDialog ->
|
||||
dialog.title == replaceAllDialogTitle
|
||||
}
|
||||
showWarningIfPopupClosed(true)
|
||||
test {
|
||||
ideFrame {
|
||||
Thread.sleep(300)
|
||||
button(replaceAllButtonText).click()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
task {
|
||||
val replaceButtonText = FindBundle.message("find.replace.command")
|
||||
text(LessonsBundle.message("find.in.files.confirm.replace", strong(replaceButtonText)))
|
||||
stateCheck { editor.document.charsSequence.contains("orange") }
|
||||
restoreByUi(delayMillis = defaultRestoreDelay)
|
||||
test {
|
||||
ideFrame {
|
||||
Thread.sleep(300)
|
||||
findMessageDialog(replaceAllDialogTitle).click(replaceButtonText)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun TaskRuntimeContext.getFindPopup(): FindPopupPanel? {
|
||||
return UIUtil.getParentOfType(FindPopupPanel::class.java, focusOwner)
|
||||
}
|
||||
|
||||
private fun TaskContext.highlightAndTriggerWhenButtonSelected(buttonText: String) {
|
||||
triggerByUiComponentAndHighlight { button: ActionButton ->
|
||||
button.action.templateText == buttonText
|
||||
}
|
||||
triggerByUiComponentAndHighlight(false, false) { button: ActionButton ->
|
||||
button.action.templateText == buttonText && button.isSelected
|
||||
}
|
||||
}
|
||||
|
||||
private fun JTable.findLastRowIndexOfItemWithText(textToFind: String): Int {
|
||||
for (ind in (rowCount - 1) downTo 0) {
|
||||
val item = getValueAt(ind, 0) as? UsagePresentation
|
||||
if (item?.plainText?.contains(textToFind, true) == true) {
|
||||
return ind
|
||||
}
|
||||
}
|
||||
return -1
|
||||
}
|
||||
|
||||
private fun TaskContext.showWarningIfPopupClosed(isReplacePopup: Boolean) {
|
||||
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
|
||||
}
|
||||
}
|
||||
|
||||
private fun LessonContext.resetFindSettings() {
|
||||
prepareRuntimeTask {
|
||||
FindManager.getInstance(project).findInProjectModel.apply {
|
||||
isWholeWordsOnly = false
|
||||
stringToFind = ""
|
||||
stringToReplace = ""
|
||||
directoryName = null
|
||||
}
|
||||
val settings = FindInProjectSettings.getInstance(project) as? FindInProjectSettingsBase
|
||||
settings?.apply {
|
||||
findStrings.clear()
|
||||
replaceStrings.clear()
|
||||
recentDirectories.clear()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override val testScriptProperties = TaskTestContext.TestScriptProperties(10)
|
||||
}
|
||||
@@ -1,9 +1,7 @@
|
||||
// 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 training.learn.lesson.kimpl
|
||||
|
||||
import com.intellij.openapi.actionSystem.ActionManager
|
||||
import com.intellij.openapi.actionSystem.CommonDataKeys
|
||||
import com.intellij.openapi.actionSystem.DataProvider
|
||||
import com.intellij.openapi.actionSystem.*
|
||||
import com.intellij.openapi.actionSystem.impl.ActionButton
|
||||
import com.intellij.openapi.application.ApplicationManager
|
||||
import com.intellij.openapi.application.ApplicationNamesInfo
|
||||
@@ -173,6 +171,10 @@ object LessonUtil {
|
||||
return "<raw_action>$keyStroke</raw_action>"
|
||||
}
|
||||
|
||||
fun rawKeyStroke(keyStroke: KeyStroke): String {
|
||||
return "<raw_action>${KeymapUtil.getKeyStrokeText(keyStroke)}</raw_action>"
|
||||
}
|
||||
|
||||
fun rawEnter(): String = rawKeyStroke(KeyEvent.VK_ENTER)
|
||||
|
||||
fun rawCtrlEnter(): String {
|
||||
|
||||
+1
@@ -0,0 +1 @@
|
||||
FRUITS = ['pineapple', 'banana', 'apple', 'grapes', 'mango', 'melon', 'peach', 'orange']
|
||||
+13
@@ -0,0 +1,13 @@
|
||||
from warehouse.warehouse import Warehouse
|
||||
|
||||
warehouse = Warehouse()
|
||||
warehouse.add_fruits('peach', 3)
|
||||
warehouse.add_fruits('pineapple', 5)
|
||||
warehouse.add_fruits('mango', 1)
|
||||
warehouse.add_fruits('apple', 5)
|
||||
|
||||
result = warehouse.take_fruit('apple')
|
||||
if result:
|
||||
print('This apple was delicious!')
|
||||
|
||||
warehouse.print_all_fruits()
|
||||
+31
@@ -0,0 +1,31 @@
|
||||
from util.util import FRUITS
|
||||
|
||||
|
||||
class Warehouse:
|
||||
# Fruit name to amount of it in warehouse
|
||||
entry = {} # Apple, banana, etc...
|
||||
|
||||
def __init__(self) -> None:
|
||||
for fruit in FRUITS:
|
||||
self.entry[fruit] = 0
|
||||
|
||||
# fruit name from util.FRUITS (mango, apple...)
|
||||
def add_fruits(self, fruit_name, quantity) -> None:
|
||||
cur_quantity = self.entry.get(fruit_name)
|
||||
if cur_quantity is not None:
|
||||
self.entry[fruit_name] = cur_quantity + quantity
|
||||
else:
|
||||
raise KeyError(f"Not found fruit with name: {fruit_name}")
|
||||
|
||||
def take_fruit(self, fruit_name) -> bool:
|
||||
cur_quantity = self.entry.get(fruit_name)
|
||||
if cur_quantity is None:
|
||||
raise KeyError(f"Not found fruit with name: {fruit_name}")
|
||||
elif cur_quantity > 0:
|
||||
self.entry[fruit_name] = cur_quantity - 1
|
||||
return True
|
||||
return False
|
||||
|
||||
def print_all_fruits(self) -> None:
|
||||
for fruit, quantity in self.entry.items():
|
||||
print(f"{fruit}: {quantity}")
|
||||
@@ -26,6 +26,7 @@ import training.learn.lesson.general.*
|
||||
import training.learn.lesson.general.assistance.CodeFormatLesson
|
||||
import training.learn.lesson.general.assistance.ParameterInfoLesson
|
||||
import training.learn.lesson.general.assistance.QuickPopupsLesson
|
||||
import training.learn.lesson.general.navigation.FindInFilesLesson
|
||||
import training.learn.lesson.general.refactorings.ExtractMethodCocktailSortLesson
|
||||
import training.learn.lesson.general.refactorings.ExtractVariableFromBubbleLesson
|
||||
import training.learn.lesson.kimpl.LessonUtil
|
||||
@@ -111,6 +112,7 @@ class PythonLearningCourse : LearningCourseBase(PythonLanguage.INSTANCE.id) {
|
||||
PythonFileStructureLesson(it),
|
||||
PythonRecentFilesLesson(it),
|
||||
PythonSearchEverywhereLesson(it),
|
||||
FindInFilesLesson(it, lang, "src/warehouse/find_in_files_sample.py")
|
||||
)
|
||||
},
|
||||
LearningModule(name = LessonsBundle.message("run.debug.module.name"),
|
||||
|
||||
Reference in New Issue
Block a user