6.7.0 - Alpha23 - 代码编辑器支持 "-", "=", "(", "[", "{", "<" 等按键长按功能
This commit is contained in:
@@ -362,7 +362,7 @@ public class EditorMenu {
|
||||
return tryDoing(() -> mEditor.setText(""));
|
||||
}
|
||||
if (itemId == R.id.action_comment) {
|
||||
return tryDoing(mEditor.commentHelper::handle);
|
||||
return tryDoing(mEditor.commentHelper::toggle);
|
||||
}
|
||||
if (itemId == R.id.action_beautify) {
|
||||
return tryDoing(mEditorView::beautifyCode);
|
||||
|
||||
@@ -2566,7 +2566,17 @@ class EditorView : LinearLayout, OnHintClickListener, ClickCallback, ToolbarFrag
|
||||
completions[pos].let {
|
||||
when {
|
||||
// @Inspired by 抠脚本人 (https://github.com/little-alei) on Jul 13, 2023.
|
||||
it.insertText == "/" -> editor.commentHelper.handle()
|
||||
it.insertText == "/" -> editor.commentHelper.toggle()
|
||||
it.insertText == "=" -> editor.clear()
|
||||
it.insertText == "-" -> editor.deleteLine()
|
||||
it.insertText == "(" -> editor.moveCursor(-1)
|
||||
it.insertText == ")" -> editor.moveCursor(1)
|
||||
it.insertText == "[" -> editor.jumpToLineStart()
|
||||
it.insertText == "]" -> editor.jumpToLineEnd()
|
||||
it.insertText == "{" -> editor.jumpToStart()
|
||||
it.insertText == "}" -> editor.jumpToEnd()
|
||||
it.insertText == "<" -> editor.jumpToPrevLine()
|
||||
it.insertText == ">" -> editor.jumpToNextLine()
|
||||
it.url != null -> showManual(it.url, it.hint)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,48 +5,42 @@ import android.os.Looper;
|
||||
import android.util.AttributeSet;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewConfiguration;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.TextView;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
|
||||
import org.autojs.autojs.model.autocomplete.CodeCompletions;
|
||||
import org.autojs.autojs.groundwork.WrapContentLinearLayoutManager;
|
||||
import org.autojs.autojs.model.autocomplete.CodeCompletions;
|
||||
import org.autojs.autojs.util.ViewUtils;
|
||||
import org.autojs.autojs6.R;
|
||||
|
||||
/**
|
||||
* Created by Stardust on Feb 17, 2017.
|
||||
* Modified by SuperMonster003 as of Mar 8, 2026.
|
||||
*/
|
||||
public class CodeCompletionBar extends RecyclerView {
|
||||
|
||||
public interface OnHintClickListener {
|
||||
void onHintClick(CodeCompletions completions, int pos);
|
||||
|
||||
void onHintLongClick(CodeCompletions completions, int pos);
|
||||
}
|
||||
|
||||
private int mTextColor;
|
||||
private CodeCompletions mCodeCompletions;
|
||||
private OnHintClickListener mOnHintClickListener;
|
||||
private final OnClickListener mOnCodeCompletionItemClickListener = new OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
int position = getChildViewHolder(v).getAdapterPosition();
|
||||
int position = getChildViewHolder(v).getBindingAdapterPosition();
|
||||
if (position >= 0 && position < mCodeCompletions.size()) {
|
||||
if (mOnHintClickListener != null) {
|
||||
mOnHintClickListener.onHintClick(mCodeCompletions, position);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
};
|
||||
|
||||
private final OnLongClickListener mOnCodeCompletionItemLongClickListener = new OnLongClickListener() {
|
||||
@Override
|
||||
public boolean onLongClick(View v) {
|
||||
int position = getChildViewHolder(v).getAdapterPosition();
|
||||
int position = getChildViewHolder(v).getBindingAdapterPosition();
|
||||
if (position < 0 || position >= mCodeCompletions.size())
|
||||
return false;
|
||||
if (mOnHintClickListener != null) {
|
||||
@@ -127,7 +121,18 @@ public class CodeCompletionBar extends RecyclerView {
|
||||
super(itemView);
|
||||
itemView.setOnClickListener(mOnCodeCompletionItemClickListener);
|
||||
itemView.setOnLongClickListener(mOnCodeCompletionItemLongClickListener);
|
||||
itemView.setOnTouchListener(
|
||||
new ViewUtils.DelayedLongPressTouchListener(
|
||||
itemView.getContext(),
|
||||
(long) (ViewConfiguration.getLongPressTimeout() * 1.25)
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
public interface OnHintClickListener {
|
||||
void onHintClick(CodeCompletions completions, int pos);
|
||||
|
||||
void onHintLongClick(CodeCompletions completions, int pos);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,6 +6,7 @@ import android.graphics.Canvas
|
||||
import android.os.Handler
|
||||
import android.os.Looper
|
||||
import android.os.SystemClock
|
||||
import android.text.Layout
|
||||
import android.util.AttributeSet
|
||||
import android.view.LayoutInflater
|
||||
import android.view.MotionEvent
|
||||
@@ -316,14 +317,16 @@ class CodeEditor : HVScrollView {
|
||||
when (ev.actionMasked) {
|
||||
MotionEvent.ACTION_DOWN,
|
||||
MotionEvent.ACTION_POINTER_DOWN,
|
||||
MotionEvent.ACTION_MOVE -> {
|
||||
MotionEvent.ACTION_MOVE,
|
||||
-> {
|
||||
// Mark touching as early as possible.
|
||||
// zh-CN: 尽可能早地标记触摸中状态.
|
||||
mUserTouching = true
|
||||
}
|
||||
MotionEvent.ACTION_UP,
|
||||
MotionEvent.ACTION_CANCEL,
|
||||
MotionEvent.ACTION_POINTER_UP -> {
|
||||
MotionEvent.ACTION_POINTER_UP,
|
||||
-> {
|
||||
// Clear touching flag when gesture ends.
|
||||
// zh-CN: 手势结束时清除触摸中标记.
|
||||
mUserTouching = false
|
||||
@@ -397,6 +400,10 @@ class CodeEditor : HVScrollView {
|
||||
}
|
||||
}
|
||||
|
||||
fun clear() {
|
||||
codeEditText.setText("")
|
||||
}
|
||||
|
||||
fun jumpToStart() {
|
||||
codeEditText.setSelection(0)
|
||||
}
|
||||
@@ -417,15 +424,46 @@ class CodeEditor : HVScrollView {
|
||||
val layout = codeEditText.layout
|
||||
val line = LayoutHelper.getLineOfChar(layout, minOf(codeEditText.selectionStart, codeEditText.selectionEnd))
|
||||
if (line >= 0 && line < layout.lineCount) {
|
||||
val lineEnd = layout.getLineEnd(line)
|
||||
val text = codeEditText.text.toString()
|
||||
val finalPosition = when {
|
||||
lineEnd > 0 && text[lineEnd - 1] == '\n' -> {
|
||||
lineEnd - 1
|
||||
}
|
||||
else -> lineEnd
|
||||
}
|
||||
codeEditText.setSelection(finalPosition)
|
||||
codeEditText.setSelection(getLineEndWithoutTrailingNewline(layout, line))
|
||||
}
|
||||
}
|
||||
|
||||
fun jumpToNextLine() {
|
||||
val layout = codeEditText.layout
|
||||
val cursor = minOf(codeEditText.selectionStart, codeEditText.selectionEnd)
|
||||
val line = LayoutHelper.getLineOfChar(layout, cursor)
|
||||
jumpToLinePreservingColumn(layout, line, line + 1, cursor)
|
||||
}
|
||||
|
||||
fun jumpToPrevLine() {
|
||||
val layout = codeEditText.layout
|
||||
val cursor = minOf(codeEditText.selectionStart, codeEditText.selectionEnd)
|
||||
val line = LayoutHelper.getLineOfChar(layout, cursor)
|
||||
jumpToLinePreservingColumn(layout, line, line - 1, cursor)
|
||||
}
|
||||
|
||||
private fun jumpToLinePreservingColumn(layout: Layout, fromLine: Int, targetLine: Int, cursor: Int) {
|
||||
if (fromLine !in 0 until layout.lineCount || targetLine !in 0 until layout.lineCount) {
|
||||
return
|
||||
}
|
||||
val fromLineStart = layout.getLineStart(fromLine)
|
||||
val fromLineEnd = getLineEndWithoutTrailingNewline(layout, fromLine)
|
||||
val fromLineCursor = cursor.coerceIn(fromLineStart, fromLineEnd)
|
||||
val desiredColumn = fromLineCursor - fromLineStart
|
||||
|
||||
val targetLineStart = layout.getLineStart(targetLine)
|
||||
val targetLineEnd = getLineEndWithoutTrailingNewline(layout, targetLine)
|
||||
val targetCursor = (targetLineStart + desiredColumn).coerceAtMost(targetLineEnd)
|
||||
codeEditText.setSelection(targetCursor)
|
||||
}
|
||||
|
||||
private fun getLineEndWithoutTrailingNewline(layout: Layout, line: Int): Int {
|
||||
val lineEnd = layout.getLineEnd(line)
|
||||
val text = codeEditText.text ?: return lineEnd
|
||||
return if (lineEnd > 0 && lineEnd <= text.length && text[lineEnd - 1] == '\n') {
|
||||
lineEnd - 1
|
||||
} else {
|
||||
lineEnd
|
||||
}
|
||||
}
|
||||
|
||||
@@ -739,13 +777,19 @@ class CodeEditor : HVScrollView {
|
||||
fun onCursorChange(line: String, cursor: Int)
|
||||
}
|
||||
|
||||
inner class CommentHelper : CodeEditorCommentHelper {
|
||||
inner class CommentHelper {
|
||||
|
||||
private val prefix = "//"
|
||||
|
||||
override fun handle() = toggle()
|
||||
fun toggle() {
|
||||
if (isCommented()) {
|
||||
uncomment()
|
||||
} else {
|
||||
comment()
|
||||
}
|
||||
}
|
||||
|
||||
override fun comment() {
|
||||
fun comment() {
|
||||
var selectionEnd = codeEditText.selectionEnd
|
||||
val insetPosition = getProperWhitespaceAmount()
|
||||
var hasEverMatched = false
|
||||
@@ -776,7 +820,7 @@ class CodeEditor : HVScrollView {
|
||||
codeEditText.setSelection(selectionEnd)
|
||||
}
|
||||
|
||||
override fun uncomment() {
|
||||
fun uncomment() {
|
||||
var selectionEnd = codeEditText.selectionEnd
|
||||
|
||||
replaceSelectedLines(Regex("(\\s*)($prefix\\s?)(.*)")) { matchResult ->
|
||||
@@ -788,7 +832,7 @@ class CodeEditor : HVScrollView {
|
||||
codeEditText.setSelection(selectionEnd)
|
||||
}
|
||||
|
||||
override fun isCommented(): Boolean {
|
||||
fun isCommented(): Boolean {
|
||||
var atLeastOneWithPrefix = false
|
||||
val allMatched = getCoveredLinesText().split("\n").all {
|
||||
it.matches(Regex("\\s*")) || it
|
||||
@@ -859,4 +903,4 @@ class CodeEditor : HVScrollView {
|
||||
// # }
|
||||
// # }
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,21 +0,0 @@
|
||||
package org.autojs.autojs.ui.edit.editor;
|
||||
|
||||
public interface CodeEditorCommentHelper {
|
||||
|
||||
void handle();
|
||||
|
||||
void comment();
|
||||
|
||||
void uncomment();
|
||||
|
||||
boolean isCommented();
|
||||
|
||||
default void toggle() {
|
||||
if (isCommented()) {
|
||||
uncomment();
|
||||
} else {
|
||||
comment();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -76,6 +76,7 @@ import org.autojs.autojs.util.StringUtils.key
|
||||
import org.autojs.autojs6.R
|
||||
import kotlin.math.abs
|
||||
import kotlin.math.floor
|
||||
import kotlin.math.max
|
||||
import kotlin.math.min
|
||||
import kotlin.math.roundToInt
|
||||
import android.text.TextUtils as AndroidTextUtils
|
||||
@@ -1689,6 +1690,83 @@ object ViewUtils {
|
||||
}
|
||||
}
|
||||
|
||||
class DelayedLongPressTouchListener(context: Context, longPressDelayMs: Long) : View.OnTouchListener {
|
||||
|
||||
private val longPressDelayMs: Long
|
||||
private val touchSlop: Int
|
||||
|
||||
private var downX = 0f
|
||||
private var downY = 0f
|
||||
private var tracking = false
|
||||
private var longPressed = false
|
||||
private var pendingLongPress: Runnable? = null
|
||||
|
||||
init {
|
||||
this.longPressDelayMs = max(0, longPressDelayMs)
|
||||
this.touchSlop = ViewConfiguration.get(context).getScaledTouchSlop()
|
||||
}
|
||||
|
||||
override fun onTouch(v: View, event: MotionEvent): Boolean =
|
||||
when (event.getActionMasked()) {
|
||||
MotionEvent.ACTION_DOWN -> {
|
||||
downX = event.getX()
|
||||
downY = event.getY()
|
||||
tracking = true
|
||||
longPressed = false
|
||||
v.setPressed(true)
|
||||
|
||||
cancelPending(v)
|
||||
pendingLongPress = Runnable {
|
||||
if (tracking && v.isPressed()) {
|
||||
longPressed = v.performLongClick()
|
||||
}
|
||||
}
|
||||
v.postDelayed(pendingLongPress, longPressDelayMs)
|
||||
true
|
||||
}
|
||||
MotionEvent.ACTION_MOVE -> {
|
||||
if (tracking) {
|
||||
val dx = abs(event.getX() - downX)
|
||||
val dy = abs(event.getY() - downY)
|
||||
if (dx > touchSlop || dy > touchSlop) {
|
||||
cancelGesture(v)
|
||||
}
|
||||
}
|
||||
true
|
||||
}
|
||||
MotionEvent.ACTION_UP -> {
|
||||
cancelPending(v)
|
||||
v.setPressed(false)
|
||||
|
||||
val shouldClick = tracking && !longPressed
|
||||
tracking = false
|
||||
if (shouldClick) {
|
||||
v.performClick()
|
||||
}
|
||||
true
|
||||
}
|
||||
MotionEvent.ACTION_CANCEL -> {
|
||||
cancelGesture(v)
|
||||
true
|
||||
}
|
||||
else -> false
|
||||
}
|
||||
|
||||
private fun cancelPending(v: View) {
|
||||
if (pendingLongPress != null) {
|
||||
v.removeCallbacks(pendingLongPress)
|
||||
pendingLongPress = null
|
||||
}
|
||||
}
|
||||
|
||||
private fun cancelGesture(v: View) {
|
||||
cancelPending(v)
|
||||
v.setPressed(false)
|
||||
tracking = false
|
||||
longPressed = false
|
||||
}
|
||||
}
|
||||
|
||||
private class TextSizeScaleListener(private val textView: TextView) : ScaleGestureDetector.SimpleOnScaleGestureListener() {
|
||||
|
||||
private val mMinTextSize = 4.0f
|
||||
|
||||
Reference in New Issue
Block a user