diff --git a/app/src/main/java/com/itsaky/androidide/actions/file/ShowTooltipAction.kt b/app/src/main/java/com/itsaky/androidide/actions/file/ShowTooltipAction.kt index 3ba994a607..340a34fd05 100644 --- a/app/src/main/java/com/itsaky/androidide/actions/file/ShowTooltipAction.kt +++ b/app/src/main/java/com/itsaky/androidide/actions/file/ShowTooltipAction.kt @@ -30,7 +30,7 @@ import com.itsaky.androidide.idetooltips.TooltipTag class ShowTooltipAction(private val context: Context, override val order: Int) : EditorRelatedAction() { - override val id: String = "ide.editor.code.text.format" + override val id: String = "ide.editor.code.text.show_tooltip" override var location: ActionItem.Location = ActionItem.Location.EDITOR_TEXT_ACTIONS private var htmlString: String = "" @@ -39,6 +39,18 @@ class ShowTooltipAction(private val context: Context, override val order: Int) : icon = ContextCompat.getDrawable(context, R.drawable.ic_action_help) } + override fun prepare(data: ActionData) { + super.prepare(data) + val editor = data.getEditor() + if (editor == null) { + visible = false + enabled = false + return + } + visible = editor.cursor?.isSelected == true + enabled = visible + } + override suspend fun execAction(data: ActionData): Any { val editor = data.getEditor()!! val cursor = editor.text.cursor @@ -50,10 +62,11 @@ class ShowTooltipAction(private val context: Context, override val order: Int) : } val word = editor.text.substring(cursor.left, cursor.right) if (cursor.isSelected) { - val tag = if (category == TooltipCategory.CATEGORY_XML && editor.isXmlAttribute()) { - word.substringAfterLast(":") - } else { - word + val useEditorTag = editor.tag != null + val tag = when { + useEditorTag -> editor.tag.toString() + category == TooltipCategory.CATEGORY_XML && editor.isXmlAttribute() -> word.substringAfterLast(":") + else -> word } TooltipManager.showTooltip( context = context, diff --git a/app/src/main/java/com/itsaky/androidide/fragments/EmptyStateFragment.kt b/app/src/main/java/com/itsaky/androidide/fragments/EmptyStateFragment.kt index f00ccd6ad2..b99add1f02 100644 --- a/app/src/main/java/com/itsaky/androidide/fragments/EmptyStateFragment.kt +++ b/app/src/main/java/com/itsaky/androidide/fragments/EmptyStateFragment.kt @@ -13,6 +13,7 @@ import androidx.lifecycle.repeatOnLifecycle import androidx.viewbinding.ViewBinding import com.itsaky.androidide.databinding.FragmentEmptyStateBinding import com.itsaky.androidide.editor.ui.EditorLongPressEvent +import com.itsaky.androidide.editor.ui.IDEEditor import com.itsaky.androidide.idetooltips.TooltipManager import com.itsaky.androidide.utils.viewLifecycleScope import com.itsaky.androidide.viewmodel.EmptyStateFragmentViewModel @@ -40,16 +41,31 @@ abstract class EmptyStateFragment : FragmentWithBinding { @Volatile private var cachedIsEmpty: Boolean = true + open val currentEditor: IDEEditor? get() = null + /** * Called when a long press is detected on the fragment's root view. * Subclasses must implement this to define the action (e.g., show a tooltip). */ - protected abstract fun onFragmentLongPressed() + open fun onFragmentLongPressed(x: Float = -1f, y: Float = -1f) { + currentEditor?.let { editor -> + if (x >= 0 && y >= 0) { + editor.setSelectionFromPoint(x, y) + } + } + onFragmentLongPressed() + } + + open fun onFragmentLongPressed() { + val currentEditor = currentEditor ?: return + currentEditor.selectCurrentWord() + } private val gestureListener = object : GestureDetector.SimpleOnGestureListener() { override fun onLongPress(e: MotionEvent) { - onFragmentLongPressed() + if (currentEditor?.isReadOnlyContext == true) return + onFragmentLongPressed(e.x, e.y) } } @@ -160,6 +176,7 @@ abstract class EmptyStateFragment : FragmentWithBinding { // This method will be called when an EditorLongPressEvent is posted @Subscribe(threadMode = ThreadMode.MAIN) fun onEditorLongPressed(event: EditorLongPressEvent) { - onFragmentLongPressed() + val motionEvent = event.motionEvent + onFragmentLongPressed(motionEvent.x, motionEvent.y) } } diff --git a/app/src/main/java/com/itsaky/androidide/fragments/output/BuildOutputFragment.kt b/app/src/main/java/com/itsaky/androidide/fragments/output/BuildOutputFragment.kt index b440808f55..cd67c67f04 100644 --- a/app/src/main/java/com/itsaky/androidide/fragments/output/BuildOutputFragment.kt +++ b/app/src/main/java/com/itsaky/androidide/fragments/output/BuildOutputFragment.kt @@ -20,12 +20,11 @@ import android.os.Bundle import android.view.View import com.blankj.utilcode.util.ThreadUtils import com.itsaky.androidide.R +import com.itsaky.androidide.editor.ui.IDEEditor import com.itsaky.androidide.idetooltips.TooltipTag class BuildOutputFragment : NonEditableEditorFragment() { - override fun onFragmentLongPressed() { - showTooltipDialog(TooltipTag.PROJECT_BUILD_OUTPUT) - } + override val currentEditor: IDEEditor? get() = editor private val unsavedLines: MutableList = ArrayList() @@ -35,6 +34,7 @@ class BuildOutputFragment : NonEditableEditorFragment() { ) { super.onViewCreated(view, savedInstanceState) editor?.includeDebugInfoOnCopy = true + editor?.tag = TooltipTag.PROJECT_BUILD_OUTPUT emptyStateViewModel.setEmptyMessage(getString(R.string.msg_emptyview_buildoutput)) if (unsavedLines.isNotEmpty()) { for (line in unsavedLines) { diff --git a/app/src/main/java/com/itsaky/androidide/fragments/output/LogViewFragment.kt b/app/src/main/java/com/itsaky/androidide/fragments/output/LogViewFragment.kt index 0aa3091fd9..403d4c2475 100644 --- a/app/src/main/java/com/itsaky/androidide/fragments/output/LogViewFragment.kt +++ b/app/src/main/java/com/itsaky/androidide/fragments/output/LogViewFragment.kt @@ -28,6 +28,7 @@ import com.itsaky.androidide.editor.language.treesitter.LogLanguage import com.itsaky.androidide.editor.language.treesitter.TreeSitterLanguageProvider import com.itsaky.androidide.editor.schemes.IDEColorScheme import com.itsaky.androidide.editor.schemes.IDEColorSchemeProvider +import com.itsaky.androidide.editor.ui.IDEEditor import com.itsaky.androidide.fragments.EmptyStateFragment import com.itsaky.androidide.fragments.output.LogViewFragment.Companion.LOG_FREQUENCY import com.itsaky.androidide.fragments.output.LogViewFragment.Companion.MAX_CHUNK_SIZE @@ -126,6 +127,8 @@ abstract class LogViewFragment : } } + override val currentEditor: IDEEditor? get() = _binding?.editor + fun appendLog(line: LogLine) { val lineString = if (isSimpleFormattingEnabled()) { @@ -222,6 +225,7 @@ abstract class LogViewFragment : editor.typefaceText = jetbrainsMono() editor.isEnsurePosAnimEnabled = false editor.includeDebugInfoOnCopy = true + editor.tag = tooltipTag editor.cursorAnimator = object : CursorAnimator { override fun markStartPos() {} @@ -280,8 +284,4 @@ abstract class LogViewFragment : emptyStateViewModel.setEmpty(true) } } - - override fun onFragmentLongPressed() { - showTooltipDialog(tooltipTag) - } } diff --git a/editor/src/main/java/com/itsaky/androidide/editor/ui/IDEEditor.kt b/editor/src/main/java/com/itsaky/androidide/editor/ui/IDEEditor.kt index 6429ffbcc9..5b8742f22f 100644 --- a/editor/src/main/java/com/itsaky/androidide/editor/ui/IDEEditor.kt +++ b/editor/src/main/java/com/itsaky/androidide/editor/ui/IDEEditor.kt @@ -1131,4 +1131,20 @@ constructor( ) { editorFeatures.setSelectionAround(line, column) } + + fun setSelectionFromPoint(x: Float, y: Float) { + if (isReleased) return + + try { + val packedPos = getPointPosition(x, y) + + val line = (packedPos ushr 32).toInt() + val column = (packedPos and 0xffffffffL).toInt() + if (line < 0 || column < 0) return + + setSelection(line, column) + } catch (e: Exception) { + log.error("Error setting selection from point", e) + } + } }