diff --git a/.idea/misc.xml b/.idea/misc.xml
index 0aba872b6..30ab9a6cb 100755
--- a/.idea/misc.xml
+++ b/.idea/misc.xml
@@ -39,6 +39,8 @@
+
+
@@ -66,11 +68,13 @@
+
+
diff --git a/actions/src/main/java/com/itsaky/androidide/actions/ActionItem.kt b/actions/src/main/java/com/itsaky/androidide/actions/ActionItem.kt
index 7b12c6e75..2d5ee4365 100644
--- a/actions/src/main/java/com/itsaky/androidide/actions/ActionItem.kt
+++ b/actions/src/main/java/com/itsaky/androidide/actions/ActionItem.kt
@@ -62,16 +62,19 @@ interface ActionItem {
enum class Location(val id: String) {
/** Location marker for action items shown in editor activity's toolbar. */
- EDITOR_TOOLBAR("editor_toolbar"),
+ EDITOR_TOOLBAR("editor.activity.toolbar"),
/** Location marker for action items shown in editor's text action menu. */
- EDITOR_TEXT_ACTIONS("editor_text_actions"),
+ EDITOR_TEXT_ACTIONS("editor.textActions"),
/**
* Location marker for action items shown in 'Code actions' submenu in editor's text action
* menu.
*/
- EDITOR_CODE_ACTIONS("editor_code_actions");
+ EDITOR_CODE_ACTIONS("editor.codeActions"),
+
+ /** Location marker for action items show in 'Find & Replace' action mode menu in editor. */
+ EDITOR_SEARCH_ACTION_MODE("editor.searchActionMode");
override fun toString(): String {
return id
diff --git a/app/src/main/java/com/itsaky/androidide/actions/editor/find/GoToNextAction.kt b/app/src/main/java/com/itsaky/androidide/actions/editor/find/GoToNextAction.kt
new file mode 100644
index 000000000..ad49591ad
--- /dev/null
+++ b/app/src/main/java/com/itsaky/androidide/actions/editor/find/GoToNextAction.kt
@@ -0,0 +1,45 @@
+/*
+ * This file is part of AndroidIDE.
+ *
+ * AndroidIDE is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * AndroidIDE is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with AndroidIDE. If not, see .
+ */
+
+package com.itsaky.androidide.actions.editor.find
+
+import android.content.Context
+import androidx.core.content.ContextCompat
+import com.itsaky.androidide.R
+import com.itsaky.androidide.actions.ActionData
+
+/**
+ * 'Go to next' action in editor's search action mode.
+ * @author Akash Yadav
+ */
+class GoToNextAction() : SearchActionModeAction() {
+ override val id: String = "editor.find.next"
+
+ constructor(context: Context) : this() {
+ label = context.getString(R.string.next)
+ icon = ContextCompat.getDrawable(context, R.drawable.ic_search_next)
+ }
+
+ override fun execAction(data: ActionData): Any {
+ val editor = getEditor(data)!!
+ if (!editor.searcher.hasQuery()) {
+ return false
+ }
+
+ return editor.searcher.gotoNext()
+ }
+}
diff --git a/app/src/main/java/com/itsaky/androidide/actions/editor/find/GoToPreviousAction.kt b/app/src/main/java/com/itsaky/androidide/actions/editor/find/GoToPreviousAction.kt
new file mode 100644
index 000000000..346102273
--- /dev/null
+++ b/app/src/main/java/com/itsaky/androidide/actions/editor/find/GoToPreviousAction.kt
@@ -0,0 +1,46 @@
+/*
+ * This file is part of AndroidIDE.
+ *
+ * AndroidIDE is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * AndroidIDE is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with AndroidIDE. If not, see .
+ */
+
+package com.itsaky.androidide.actions.editor.find
+
+import android.content.Context
+import androidx.core.content.ContextCompat
+import com.itsaky.androidide.R
+import com.itsaky.androidide.R.string
+import com.itsaky.androidide.actions.ActionData
+
+/**
+ * 'Go to previous' action in editor's search action mode.
+ * @author Akash Yadav
+ */
+class GoToPreviousAction() : SearchActionModeAction() {
+ override val id: String = "editor.find.previous"
+
+ constructor(context: Context) : this() {
+ label = context.getString(string.previous)
+ icon = ContextCompat.getDrawable(context, R.drawable.ic_search_previous)
+ }
+
+ override fun execAction(data: ActionData): Any {
+ val editor = getEditor(data)!!
+ if (!editor.searcher.hasQuery()) {
+ return false
+ }
+
+ return editor.searcher.gotoPrevious()
+ }
+}
diff --git a/app/src/main/java/com/itsaky/androidide/actions/editor/find/ReplaceAction.kt b/app/src/main/java/com/itsaky/androidide/actions/editor/find/ReplaceAction.kt
new file mode 100644
index 000000000..b28f0a38d
--- /dev/null
+++ b/app/src/main/java/com/itsaky/androidide/actions/editor/find/ReplaceAction.kt
@@ -0,0 +1,87 @@
+/*
+ * This file is part of AndroidIDE.
+ *
+ * AndroidIDE is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * AndroidIDE is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with AndroidIDE. If not, see .
+ */
+
+package com.itsaky.androidide.actions.editor.find
+
+import android.content.Context
+import android.view.LayoutInflater
+import androidx.appcompat.view.ActionMode
+import androidx.core.content.ContextCompat
+import com.itsaky.androidide.R
+import com.itsaky.androidide.actions.ActionData
+import com.itsaky.androidide.databinding.LayoutEditorFindReplaceBinding
+import com.itsaky.androidide.utils.DialogUtils
+import com.itsaky.androidide.utils.Logger
+
+/**
+ * Shows dialog to replace one or all the matched text in editor searcher.
+ * @author Akash Yadav
+ */
+class ReplaceAction() : SearchActionModeAction() {
+
+ override val id: String = "editor.search.replace"
+ private val log = Logger.newInstance(javaClass.simpleName)
+
+ constructor(context: Context) : this() {
+ label = context.getString(R.string.replace)
+ icon = ContextCompat.getDrawable(context, R.drawable.ic_search_replace)
+ }
+
+ override fun execAction(data: ActionData): Any {
+ val context = data[Context::class.java]!!
+ val editor = getEditor(data)!!
+
+ if (!editor.searcher.hasQuery()) {
+ return false
+ }
+
+ val binding = LayoutEditorFindReplaceBinding.inflate(LayoutInflater.from(context))
+ val builder = DialogUtils.newMaterialDialogBuilder(context)
+ builder.setTitle(R.string.replace)
+ builder.setView(binding.root)
+ builder.setNegativeButton(android.R.string.cancel, null)
+ builder.setPositiveButton(R.string.replace) { dialog, _ ->
+ dialog.dismiss()
+ val input = binding.replacementInput.editText
+ if (input == null) {
+ log.error("Unable to perform replace action. Input field is null")
+ return@setPositiveButton
+ }
+
+ editor.searcher.replaceThis(input.text.toString())
+ }
+ builder.setNeutralButton(R.string.replaceAll) { dialog, _ ->
+ dialog.dismiss()
+ val input = binding.replacementInput.editText
+ if (input == null) {
+ log.error("Unable to perform replace action. Input field is null")
+ return@setNeutralButton
+ }
+
+ editor.searcher.replaceAllAsync(input.text.toString()).whenComplete { _, error ->
+ if (error != null) {
+ log.error("Unable to replace all matched text", error)
+ } else {
+ editor.post { data[ActionMode::class.java]?.finish() }
+ }
+ }
+ }
+ builder.show()
+
+ return true
+ }
+}
diff --git a/app/src/main/java/com/itsaky/androidide/actions/editor/find/SearchActionModeAction.kt b/app/src/main/java/com/itsaky/androidide/actions/editor/find/SearchActionModeAction.kt
new file mode 100644
index 000000000..cc83e257c
--- /dev/null
+++ b/app/src/main/java/com/itsaky/androidide/actions/editor/find/SearchActionModeAction.kt
@@ -0,0 +1,27 @@
+/*
+ * This file is part of AndroidIDE.
+ *
+ * AndroidIDE is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * AndroidIDE is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with AndroidIDE. If not, see .
+ */
+
+package com.itsaky.androidide.actions.editor.find
+
+import com.itsaky.androidide.actions.ActionItem
+import com.itsaky.androidide.actions.ActionItem.Location
+import com.itsaky.androidide.actions.EditorRelatedAction
+
+/** @author Akash Yadav */
+abstract class SearchActionModeAction : EditorRelatedAction() {
+ override var location: Location = ActionItem.Location.EDITOR_SEARCH_ACTION_MODE
+}
diff --git a/app/src/main/java/com/itsaky/androidide/utils/EditorActivityActions.kt b/app/src/main/java/com/itsaky/androidide/utils/EditorActivityActions.kt
index b6d2d0fd7..16bbeafc3 100644
--- a/app/src/main/java/com/itsaky/androidide/utils/EditorActivityActions.kt
+++ b/app/src/main/java/com/itsaky/androidide/utils/EditorActivityActions.kt
@@ -45,6 +45,9 @@ import com.itsaky.androidide.actions.editor.CutAction
import com.itsaky.androidide.actions.editor.ExpandSelectionAction
import com.itsaky.androidide.actions.editor.PasteAction
import com.itsaky.androidide.actions.editor.SelectAllAction
+import com.itsaky.androidide.actions.editor.find.GoToNextAction
+import com.itsaky.androidide.actions.editor.find.GoToPreviousAction
+import com.itsaky.androidide.actions.editor.find.ReplaceAction
import com.itsaky.androidide.actions.etc.DaemonStatusAction
import com.itsaky.androidide.actions.etc.FileTreeAction
import com.itsaky.androidide.actions.etc.FindActionMenu
@@ -84,6 +87,11 @@ class EditorActivityActions {
registry.registerAction(CopyAction(context))
registry.registerAction(PasteAction(context))
registry.registerAction(FormatCodeAction(context))
+
+ // editor search actions
+ registry.registerAction(GoToNextAction(context))
+ registry.registerAction(GoToPreviousAction(context))
+ registry.registerAction(ReplaceAction(context))
}
@JvmStatic
diff --git a/app/src/main/java/com/itsaky/androidide/views/editor/IDEEditor.java b/app/src/main/java/com/itsaky/androidide/views/editor/IDEEditor.java
index 5fa652324..dc7bac022 100644
--- a/app/src/main/java/com/itsaky/androidide/views/editor/IDEEditor.java
+++ b/app/src/main/java/com/itsaky/androidide/views/editor/IDEEditor.java
@@ -25,6 +25,7 @@ import android.view.inputmethod.EditorInfo;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
+import androidx.appcompat.app.AppCompatActivity;
import com.blankj.utilcode.util.ThreadUtils;
import com.itsaky.androidide.R;
@@ -34,10 +35,8 @@ import com.itsaky.androidide.language.IDELanguage;
import com.itsaky.androidide.lsp.IDELanguageClientImpl;
import com.itsaky.androidide.managers.PreferenceManager;
import com.itsaky.androidide.syntax.colorschemes.SchemeAndroidIDE;
-import com.itsaky.androidide.utils.DialogUtils;
import com.itsaky.androidide.utils.Logger;
import com.itsaky.lsp.api.ILanguageServer;
-import com.itsaky.lsp.models.CodeActionItem;
import com.itsaky.lsp.models.Command;
import com.itsaky.lsp.models.DefinitionResult;
import com.itsaky.lsp.models.DiagnosticItem;
@@ -65,6 +64,7 @@ import io.github.rosemoe.sora.event.ContentChangeEvent;
import io.github.rosemoe.sora.event.SelectionChangeEvent;
import io.github.rosemoe.sora.event.Unsubscribe;
import io.github.rosemoe.sora.widget.CodeEditor;
+import io.github.rosemoe.sora.widget.IDEEditorSearcher;
import io.github.rosemoe.sora.widget.component.EditorAutoCompletion;
import io.github.rosemoe.sora.widget.component.EditorTextActionWindow;
@@ -73,6 +73,7 @@ public class IDEEditor extends CodeEditor {
public static final String KEY_FILE = "editor_file";
private static final Logger LOG = Logger.newInstance("IDEEditor");
private final EditorActionsMenu mActionsPopup;
+ private IDEEditorSearcher mSearcher;
private int mFileVersion;
private File file;
private ILanguageServer mLanguageServer;
@@ -99,6 +100,7 @@ public class IDEEditor extends CodeEditor {
mActionsPopup.init();
setColorScheme(new SchemeAndroidIDE());
+ setSearcher(new IDEEditorSearcher(this));
getComponent(EditorTextActionWindow.class).setEnabled(false);
subscribeEvent(SelectionChangeEvent.class, this::handleSelectionChange);
subscribeEvent(ContentChangeEvent.class, this::handleContentChange);
@@ -857,15 +859,23 @@ public class IDEEditor extends CodeEditor {
return new Range(start, end);
}
-
- /**
- * Tells the language client to perform the given code action item.
- *
- * @param action The action to perform.
- */
- public void performCodeAction(CodeActionItem action) {
- if (mLanguageClient != null) {
- mLanguageClient.performCodeAction(this, action);
+
+ @Override
+ public IDEEditorSearcher getSearcher() {
+ return mSearcher;
+ }
+
+ protected void setSearcher(@NonNull IDEEditorSearcher searcher) {
+ mSearcher = searcher;
+ }
+
+ @Override
+ public void beginSearchMode() {
+ final var callback = new SearchActionMode(this);
+ if (getContext() instanceof AppCompatActivity) {
+ startActionMode (callback);
+ } else {
+ LOG.error("Unable start search action mode. Activity must inherit AppCompatActivity.");
}
}
}
diff --git a/app/src/main/java/com/itsaky/androidide/views/editor/SearchActionMode.kt b/app/src/main/java/com/itsaky/androidide/views/editor/SearchActionMode.kt
new file mode 100644
index 000000000..29cd94f1d
--- /dev/null
+++ b/app/src/main/java/com/itsaky/androidide/views/editor/SearchActionMode.kt
@@ -0,0 +1,107 @@
+/*
+ * This file is part of AndroidIDE.
+ *
+ * AndroidIDE is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * AndroidIDE is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with AndroidIDE. If not, see .
+ */
+
+package com.itsaky.androidide.views.editor
+
+import android.annotation.SuppressLint
+import android.content.Context
+import android.text.TextUtils
+import android.view.ActionMode
+import android.view.Menu
+import android.view.MenuItem
+import androidx.appcompat.view.menu.MenuBuilder
+import androidx.appcompat.widget.SearchView
+import com.itsaky.androidide.actions.ActionData
+import com.itsaky.androidide.actions.ActionItem
+import com.itsaky.androidide.actions.ActionsRegistry
+import io.github.rosemoe.sora.R
+import io.github.rosemoe.sora.widget.CodeEditor
+import io.github.rosemoe.sora.widget.EditorSearcher.SearchOptions
+
+/**
+ * Action mode for find and replace functions in editor.
+ * @author Akash Yadav
+ */
+class SearchActionMode(val editor: IDEEditor) : ActionMode.Callback {
+
+ @SuppressLint("RestrictedApi")
+ override fun onCreateActionMode(mode: ActionMode?, menu: Menu?): Boolean {
+
+ if (mode == null) {
+ return false
+ }
+
+ if (menu is MenuBuilder) {
+ menu.setOptionalIconsVisible(true)
+ }
+
+ val search = SearchView(editor.context)
+ search.setOnQueryTextListener(OnQueryListener(editor))
+ search.isIconified = false
+ search.queryHint = editor.context.getString(R.string.text_to_search)
+ search.performClick()
+ search.setIconifiedByDefault(false)
+ mode.customView = search
+ return true
+ }
+
+ override fun onPrepareActionMode(mode: ActionMode?, menu: Menu?): Boolean {
+ if (mode == null || menu == null) {
+ return false
+ }
+
+ menu.clear()
+ val registry = ActionsRegistry.getInstance()
+ registry.fillMenu(createData(mode), ActionItem.Location.EDITOR_SEARCH_ACTION_MODE, menu)
+
+ return true
+ }
+
+ override fun onActionItemClicked(mode: ActionMode?, item: MenuItem?): Boolean {
+ return true
+ }
+
+ override fun onDestroyActionMode(mode: ActionMode?) {
+ editor.searcher.stopSearch()
+ }
+
+ private fun createData(mode: ActionMode): ActionData {
+ return ActionData().apply {
+ put(Context::class.java, editor.context)
+ put(IDEEditor::class.java, editor)
+ put(CodeEditor::class.java, editor)
+ put(ActionMode::class.java, mode)
+ }
+ }
+
+ private class OnQueryListener(val editor: IDEEditor) : SearchView.OnQueryTextListener {
+ override fun onQueryTextSubmit(query: String?): Boolean {
+ editor.searcher.gotoNext()
+ return false
+ }
+
+ override fun onQueryTextChange(newText: String?): Boolean {
+ if (TextUtils.isEmpty(newText)) {
+ editor.searcher.stopSearch()
+ return false
+ }
+
+ editor.searcher.search(newText!!, SearchOptions(false, false))
+ return false
+ }
+ }
+}
diff --git a/app/src/main/java/io/github/rosemoe/sora/widget/IDEEditorSearcher.kt b/app/src/main/java/io/github/rosemoe/sora/widget/IDEEditorSearcher.kt
new file mode 100644
index 000000000..0426f772a
--- /dev/null
+++ b/app/src/main/java/io/github/rosemoe/sora/widget/IDEEditorSearcher.kt
@@ -0,0 +1,117 @@
+/*
+ * This file is part of AndroidIDE.
+ *
+ * AndroidIDE is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * AndroidIDE is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with AndroidIDE. If not, see .
+ */
+
+@file:Suppress("DEPRECATION")
+
+package io.github.rosemoe.sora.widget
+
+import android.app.ProgressDialog
+import android.widget.Toast
+import com.itsaky.androidide.R.string
+import com.itsaky.androidide.utils.Logger
+import com.itsaky.androidide.views.editor.IDEEditor
+import io.github.rosemoe.sora.text.TextUtils
+import io.github.rosemoe.sora.util.IntPair
+import java.util.concurrent.*
+
+/**
+ * Search text in editor. As the constructor of [EditorSearcher] is package private, we cannot
+ * extend it in another package. So we put this class in the same package.
+ *
+ * @author Akash Yadav
+ */
+open class IDEEditorSearcher(editor: IDEEditor) : EditorSearcher(editor) {
+
+ private val log = Logger.newInstance(javaClass.simpleName)
+
+ protected fun getEditor(): CodeEditor {
+ try {
+ val field = EditorSearcher::class.java.getDeclaredField("mEditor")
+ field.isAccessible = true
+ return field.get(this) as CodeEditor
+ } catch (error: Throwable) {
+ throw RuntimeException("Unable get instance of editor", error)
+ }
+ }
+
+ fun replaceAllAsync(replacement: String): CompletableFuture {
+ val dialog =
+ ProgressDialog.show(
+ getEditor().context,
+ getEditor().context.getString(string.replaceAll),
+ getEditor().context.getString(string.msg_replacing),
+ true,
+ false)
+ return CompletableFuture.runAsync { replaceAll(replacement) }.thenAccept {
+ getEditor().post { dialog.dismiss() }
+ }
+ }
+
+ override fun replaceAll(replacement: String) {
+ checkState()
+ if (!isResultValid) {
+ Toast.makeText(getEditor().context, "Editor is still preparing", Toast.LENGTH_SHORT)
+ .show()
+ return
+ }
+
+ val res = mLastResults
+ try {
+ val sb = getEditor().text.toStringBuilder()
+ val newLength = replacement.length
+ if (mOptions.useRegex) {
+ var delta = 0
+ for (i in 0 until res.size()) {
+ val region = res[i]
+ val start = IntPair.getFirst(region)
+ val end = IntPair.getSecond(region)
+ val oldLength = end - start
+ sb.replace(start + delta, end + delta, replacement)
+ delta += newLength - oldLength
+ }
+ } else {
+ var fromIndex = 0
+ var foundIndex: Int
+ while (TextUtils.indexOf(sb, mPattern, mOptions.ignoreCase, fromIndex).also {
+ foundIndex = it
+ } != -1) {
+ sb.replace(foundIndex, foundIndex + mPattern.length, replacement)
+ fromIndex = foundIndex + newLength
+ }
+ }
+ getEditor().post {
+ val pos = getEditor().cursor.left()
+ // stopSearch();
+ getEditor()
+ .text
+ .replace(
+ 0,
+ 0,
+ getEditor().lineCount - 1,
+ getEditor().text.getColumnCount(getEditor().lineCount - 1),
+ sb)
+ getEditor().setSelectionAround(pos.line, pos.column)
+ }
+ } catch (e: Exception) {
+ log.error("Failed to replace", e)
+ }
+ }
+
+ private fun checkState() {
+ check(hasQuery()) { "pattern not set" }
+ }
+}
diff --git a/app/src/main/res/drawable/ic_search_next.xml b/app/src/main/res/drawable/ic_search_next.xml
new file mode 100644
index 000000000..8fd5a6c6b
--- /dev/null
+++ b/app/src/main/res/drawable/ic_search_next.xml
@@ -0,0 +1,5 @@
+
+
+
diff --git a/app/src/main/res/drawable/ic_search_previous.xml b/app/src/main/res/drawable/ic_search_previous.xml
new file mode 100644
index 000000000..d81a72f3b
--- /dev/null
+++ b/app/src/main/res/drawable/ic_search_previous.xml
@@ -0,0 +1,5 @@
+
+
+
diff --git a/app/src/main/res/drawable/ic_search_replace.xml b/app/src/main/res/drawable/ic_search_replace.xml
new file mode 100644
index 000000000..dcd686788
--- /dev/null
+++ b/app/src/main/res/drawable/ic_search_replace.xml
@@ -0,0 +1,5 @@
+
+
+
diff --git a/app/src/main/res/layout/layout_editor_find_replace.xml b/app/src/main/res/layout/layout_editor_find_replace.xml
new file mode 100644
index 000000000..02d7d0da0
--- /dev/null
+++ b/app/src/main/res/layout/layout_editor_find_replace.xml
@@ -0,0 +1,44 @@
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
index 5e08e1bd8..df82119d6 100755
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -349,6 +349,10 @@
Visible password flag
Use for visible password input type flag in editor. This makes sure that no suggestions are proposed by soft keyboard.
No code actions found
+ Previous
+ Case sensitive
+ Regex
+ Replacing...