From a2c46d0787ff6f58fed5f8f07256760ebef7e91f Mon Sep 17 00:00:00 2001 From: hyb1996 <946994919@qq.com> Date: Sat, 8 Sep 2018 17:30:01 +0800 Subject: [PATCH] feat(debug): supports debugging across files; supports watching variables; supports evaluate code on debug; --- .../org/autojs/autojs/ui/edit/EditorMenu.java | 11 +- .../org/autojs/autojs/ui/edit/EditorView.java | 35 +++- .../edit/debug/CodeEvaluateDialogBuilder.java | 56 +++++ .../autojs/ui/edit/debug/CodeEvaluator.java | 5 + .../autojs/autojs/ui/edit/debug/DebugBar.java | 165 +++++++++++++++ .../ui/edit/debug/WatchingVariable.java | 53 +++++ .../autojs/ui/edit/editor/CodeEditText.java | 40 ++-- .../autojs/ui/edit/editor/CodeEditor.java | 21 +- .../ui/edit/editor/TextViewRedoUndo.java | 18 ++ .../ui/edit/toolbar/DebugToolbarFragment.java | 197 +++++++++++++++--- .../edit/toolbar/NormalToolbarFragment.java | 4 - .../ui/edit/toolbar/ToolbarFragment.java | 20 +- .../autojs/ui/main/drawer/DrawerFragment.java | 2 +- .../autojs/autojs/ui/widget/AutoAdapter.java | 36 +++- .../autojs/ui/widget/ViewHolderSupplier.java | 32 +-- .../res/drawable-xhdpi/ic_connect_to_pc.png | Bin 0 -> 3196 bytes app/src/main/res/drawable-xhdpi/ic_debug.png | Bin 3196 -> 2502 bytes .../{ic_debug.png => ic_connect_to_pc.png} | Bin app/src/main/res/drawable/ic_script.png | Bin 0 -> 3072 bytes app/src/main/res/layout/debug_bar.xml | 54 +++++ .../main/res/layout/dialog_code_evaluate.xml | 38 ++++ app/src/main/res/layout/editor_view.xml | 7 + .../item_debug_variable_recycler_view.xml | 31 +++ app/src/main/res/menu/menu_editor.xml | 5 + app/src/main/res/values/strings.xml | 11 + .../assets/modules/object-observe-lite.min.js | 2 +- .../com/stardust/autojs/rhino/debug/Dim.java | 46 ++-- 27 files changed, 786 insertions(+), 103 deletions(-) create mode 100644 app/src/main/java/org/autojs/autojs/ui/edit/debug/CodeEvaluateDialogBuilder.java create mode 100644 app/src/main/java/org/autojs/autojs/ui/edit/debug/CodeEvaluator.java create mode 100644 app/src/main/java/org/autojs/autojs/ui/edit/debug/DebugBar.java create mode 100644 app/src/main/java/org/autojs/autojs/ui/edit/debug/WatchingVariable.java create mode 100644 app/src/main/res/drawable-xhdpi/ic_connect_to_pc.png rename app/src/main/res/drawable/{ic_debug.png => ic_connect_to_pc.png} (100%) create mode 100644 app/src/main/res/drawable/ic_script.png create mode 100644 app/src/main/res/layout/debug_bar.xml create mode 100644 app/src/main/res/layout/dialog_code_evaluate.xml create mode 100644 app/src/main/res/layout/item_debug_variable_recycler_view.xml diff --git a/app/src/main/java/org/autojs/autojs/ui/edit/EditorMenu.java b/app/src/main/java/org/autojs/autojs/ui/edit/EditorMenu.java index 9c1e39e9..a2a7dbbc 100644 --- a/app/src/main/java/org/autojs/autojs/ui/edit/EditorMenu.java +++ b/app/src/main/java/org/autojs/autojs/ui/edit/EditorMenu.java @@ -10,6 +10,7 @@ import com.stardust.pio.PFiles; import org.autojs.autojs.R; import org.autojs.autojs.ui.build.BuildActivity; import org.autojs.autojs.ui.build.BuildActivity_; +import org.autojs.autojs.ui.common.NotAskAgainDialog; import org.autojs.autojs.ui.edit.editor.CodeEditor; import org.autojs.autojs.ui.log.LogActivity_; import org.autojs.autojs.theme.dialog.ThemeColorMaterialDialogBuilder; @@ -68,7 +69,15 @@ public class EditorMenu { mEditor.addOrRemoveBreakpointAtCurrentLine(); return true; case R.id.action_launch_debugger: - mEditorView.launchDebugger(); + new NotAskAgainDialog.Builder(mEditorView.getContext(), "editor.debug.long_click_hint") + .title(R.string.text_alert) + .content(R.string.hint_long_click_run_to_debug) + .positiveText(R.string.ok) + .show(); + mEditorView.debug(); + return true; + case R.id.action_remove_all_breakpoints: + mEditor.removeAllBreakpoints(); return true; } return false; diff --git a/app/src/main/java/org/autojs/autojs/ui/edit/EditorView.java b/app/src/main/java/org/autojs/autojs/ui/edit/EditorView.java index 99199119..47c15af2 100644 --- a/app/src/main/java/org/autojs/autojs/ui/edit/EditorView.java +++ b/app/src/main/java/org/autojs/autojs/ui/edit/EditorView.java @@ -48,6 +48,7 @@ import org.autojs.autojs.model.indices.Property; import org.autojs.autojs.model.script.Scripts; import org.autojs.autojs.ui.doc.ManualDialog; import org.autojs.autojs.ui.edit.completion.CodeCompletionBar; +import org.autojs.autojs.ui.edit.debug.DebugBar; import org.autojs.autojs.ui.edit.editor.CodeEditor; import org.autojs.autojs.ui.edit.keyboard.FunctionsKeyboardHelper; import org.autojs.autojs.ui.edit.keyboard.FunctionsKeyboardView; @@ -104,6 +105,9 @@ public class EditorView extends FrameLayout implements CodeCompletionBar.OnHintC @ViewById(R.id.functions_keyboard) FunctionsKeyboardView mFunctionsKeyboard; + @ViewById(R.id.debug_bar) + DebugBar mDebugBar; + @ViewById(R.id.docs) EWebView mDocsWebView; @@ -273,8 +277,15 @@ public class EditorView extends FrameLayout implements CodeCompletionBar.OnHintC private void initNormalToolbar() { mNormalToolbar.setOnMenuItemClickListener(this); + mNormalToolbar.setOnMenuItemLongClickListener(id -> { + if(id == R.id.run){ + debug(); + return true; + } + return false; + }); Fragment fragment = getActivity().getSupportFragmentManager().findFragmentById(R.id.toolbar_menu); - if(fragment == null){ + if (fragment == null) { showNormalToolbar(); } } @@ -304,7 +315,7 @@ public class EditorView extends FrameLayout implements CodeCompletionBar.OnHintC setMenuItemStatus(R.id.undo, mEditor.canUndo()); setMenuItemStatus(R.id.redo, mEditor.canRedo()); })); - mEditor.setCursorChangeCallback(this::autoComplete); + mEditor.addCursorChangeCallback(this::autoComplete); mEditor.getCodeEditText().setTextSize(Pref.getEditorTextSize((int) ViewUtils.pxToSp(getContext(), mEditor.getCodeEditText().getTextSize()))); } @@ -312,6 +323,10 @@ public class EditorView extends FrameLayout implements CodeCompletionBar.OnHintC mAutoCompletion.onCursorChange(line, cursor); } + public DebugBar getDebugBar() { + return mDebugBar; + } + public void setTheme(Theme theme) { mEditorTheme = theme; mEditor.setTheme(theme); @@ -368,11 +383,13 @@ public class EditorView extends FrameLayout implements CodeCompletionBar.OnHintC @SuppressLint("CheckResult") public void runAndSaveFileIfNeeded() { save().observeOn(AndroidSchedulers.mainThread()) - .subscribe(s -> run()); + .subscribe(s -> run(true)); } - public void run() { - Snackbar.make(this, R.string.text_start_running, Snackbar.LENGTH_SHORT).show(); + public void run(boolean showMessage) { + if(showMessage){ + Snackbar.make(this, R.string.text_start_running, Snackbar.LENGTH_SHORT).show(); + } mScriptExecutionId = Scripts.runWithBroadcastSender(mFile).getId(); setMenuItemStatus(R.id.run, false); } @@ -534,12 +551,14 @@ public class EditorView extends FrameLayout implements CodeCompletionBar.OnHintC } - public void launchDebugger() { + public void debug() { DebugToolbarFragment debugToolbarFragment = DebugToolbarFragment_.builder() .build(); getActivity().getSupportFragmentManager().beginTransaction() .replace(R.id.toolbar_menu, debugToolbarFragment) .commit(); + mDebugBar.setVisibility(VISIBLE); + mInputMethodEnhanceBar.setVisibility(GONE); mDebugging = true; } @@ -551,6 +570,8 @@ public class EditorView extends FrameLayout implements CodeCompletionBar.OnHintC } showNormalToolbar(); mEditor.setDebuggingLine(-1); + mDebugBar.setVisibility(GONE); + mInputMethodEnhanceBar.setVisibility(VISIBLE); mDebugging = false; } @@ -622,7 +643,7 @@ public class EditorView extends FrameLayout implements CodeCompletionBar.OnHintC } @Nullable - public ScriptExecution getScriptExecution(){ + public ScriptExecution getScriptExecution() { return AutoJs.getInstance().getScriptEngineService().getScriptExecution(mScriptExecutionId); } diff --git a/app/src/main/java/org/autojs/autojs/ui/edit/debug/CodeEvaluateDialogBuilder.java b/app/src/main/java/org/autojs/autojs/ui/edit/debug/CodeEvaluateDialogBuilder.java new file mode 100644 index 00000000..d3fcecd2 --- /dev/null +++ b/app/src/main/java/org/autojs/autojs/ui/edit/debug/CodeEvaluateDialogBuilder.java @@ -0,0 +1,56 @@ +package org.autojs.autojs.ui.edit.debug; + +import android.content.Context; +import android.content.SharedPreferences; +import android.preference.PreferenceManager; +import android.support.annotation.NonNull; +import android.text.Editable; +import android.text.TextUtils; +import android.view.View; +import android.widget.EditText; +import android.widget.TextView; + +import org.autojs.autojs.R; +import org.autojs.autojs.theme.dialog.ThemeColorMaterialDialogBuilder; + +public class CodeEvaluateDialogBuilder extends ThemeColorMaterialDialogBuilder { + + private static final String KEY_CODE = CodeEvaluateDialogBuilder.class.getName() + ".code"; + private CodeEvaluator mCodeEvaluator; + private TextView mResult; + private EditText mCode; + private SharedPreferences mSharedPreferences; + + public CodeEvaluateDialogBuilder(@NonNull Context context) { + super(context); + setupViews(); + mSharedPreferences = PreferenceManager.getDefaultSharedPreferences(context); + mCode.setText(mSharedPreferences.getString(KEY_CODE, "")); + } + + private void setupViews() { + View view = View.inflate(context, R.layout.dialog_code_evaluate, null); + customView(view, true); + mResult = view.findViewById(R.id.result); + mCode = view.findViewById(R.id.code); + positiveText(R.string.text_run); + negativeText(R.string.text_close); + autoDismiss(false); + onNegative((dialog, which) -> dialog.dismiss()); + onPositive(((dialog, which) -> { + Editable code = mCode.getText(); + if (!TextUtils.isEmpty(code)) { + String codeStr = code.toString(); + mSharedPreferences.edit().putString(KEY_CODE, codeStr).apply(); + mResult.setText(mCodeEvaluator.eval(codeStr)); + } + })); + } + + public CodeEvaluateDialogBuilder codeEvaluator(CodeEvaluator evaluator) { + mCodeEvaluator = evaluator; + return this; + } + + +} diff --git a/app/src/main/java/org/autojs/autojs/ui/edit/debug/CodeEvaluator.java b/app/src/main/java/org/autojs/autojs/ui/edit/debug/CodeEvaluator.java new file mode 100644 index 00000000..c45ab2a9 --- /dev/null +++ b/app/src/main/java/org/autojs/autojs/ui/edit/debug/CodeEvaluator.java @@ -0,0 +1,5 @@ +package org.autojs.autojs.ui.edit.debug; + +public interface CodeEvaluator { + String eval(String code); +} diff --git a/app/src/main/java/org/autojs/autojs/ui/edit/debug/DebugBar.java b/app/src/main/java/org/autojs/autojs/ui/edit/debug/DebugBar.java new file mode 100644 index 00000000..30b667bb --- /dev/null +++ b/app/src/main/java/org/autojs/autojs/ui/edit/debug/DebugBar.java @@ -0,0 +1,165 @@ +package org.autojs.autojs.ui.edit.debug; + +import android.content.Context; +import android.support.annotation.NonNull; +import android.support.annotation.Nullable; +import android.support.v7.widget.LinearLayoutManager; +import android.support.v7.widget.RecyclerView; +import android.text.TextUtils; +import android.util.AttributeSet; +import android.view.View; +import android.widget.FrameLayout; +import android.widget.ImageView; +import android.widget.TextView; + +import com.stardust.util.ClipboardUtil; + +import org.autojs.autojs.R; +import org.autojs.autojs.theme.dialog.ThemeColorMaterialDialogBuilder; +import org.autojs.autojs.ui.widget.AutoAdapter; +import org.autojs.autojs.ui.widget.BindableViewHolder; + +import java.util.List; + + +public class DebugBar extends FrameLayout { + + private AutoAdapter mVariablesAdapter; + private final WatchingVariable mCurrentVariable = new WatchingVariable(null, null, true); + private TextView mTitle; + private CodeEvaluator mCodeEvaluator; + + public DebugBar(@NonNull Context context) { + super(context); + init(); + } + + public DebugBar(@NonNull Context context, @Nullable AttributeSet attrs) { + super(context, attrs); + init(); + } + + public DebugBar(@NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr) { + super(context, attrs, defStyleAttr); + init(); + } + + public void setCodeEvaluator(CodeEvaluator codeEvaluator) { + mCodeEvaluator = codeEvaluator; + } + + public List getWatchingVariables() { + return mVariablesAdapter.getData(); + } + + private void init() { + inflate(getContext(), R.layout.debug_bar, this); + mVariablesAdapter = new AutoAdapter<>(VariableViewHolder::new, R.layout.item_debug_variable_recycler_view); + RecyclerView variablesView = findViewById(R.id.variables); + variablesView.setAdapter(mVariablesAdapter); + variablesView.setLayoutManager(new LinearLayoutManager(getContext())); + mVariablesAdapter.add(mCurrentVariable); + findViewById(R.id.add).setOnClickListener(view -> showNewWatchingVariableDialog()); + findViewById(R.id.execute).setOnClickListener(view -> showExecuteCodeDialog()); + mTitle = findViewById(R.id.title); + } + + private void showExecuteCodeDialog() { + if (mCodeEvaluator == null) { + return; + } + new CodeEvaluateDialogBuilder(getContext()) + .codeEvaluator(mCodeEvaluator) + .title(R.string.text_execute_code) + .show(); + } + + + public void setTitle(String title) { + if (title == null) { + mTitle.setText(R.string.text_debug); + } else { + mTitle.setText(getResources().getString(R.string.format_debug_bar_title, title)); + } + } + + private void showNewWatchingVariableDialog() { + new ThemeColorMaterialDialogBuilder(getContext()) + .title(R.string.text_new_watching_variable) + .input(getResources().getString(R.string.text_variable_or_expr), "", (dialog, input) -> { + if (TextUtils.isEmpty(input)) { + return; + } + mVariablesAdapter.add(new WatchingVariable(input.toString())); + }) + .show(); + } + + public void updateCurrentVariable(String name, String value) { + mCurrentVariable.setDisplayName(name); + mCurrentVariable.setName(name); + mCurrentVariable.setValue(value); + mVariablesAdapter.notifyItemChanged(0); + } + + public void refresh(int start, int count) { + mVariablesAdapter.notifyItemRangeChanged(start, count); + } + + public void registerVariableChangeObserver(RecyclerView.AdapterDataObserver observer) { + mVariablesAdapter.registerAdapterDataObserver(observer); + } + + public void unregisterVariableChangeObserver(RecyclerView.AdapterDataObserver observer) { + mVariablesAdapter.unregisterAdapterDataObserver(observer); + } + + + private void showVariable(WatchingVariable variable) { + new ThemeColorMaterialDialogBuilder(getContext()) + .title(variable.getDisplayName()) + .content(variable.getValue()) + .positiveText(R.string.ok) + .negativeText(R.string.text_copy_value) + .autoDismiss(true) + .onNegative((dialog, which) -> ClipboardUtil.setClip(getContext(), variable.getValue())) + .show(); + } + + + class VariableViewHolder extends BindableViewHolder { + + private final TextView mVariable; + private final ImageView mIcon; + + VariableViewHolder(View itemView) { + super(itemView); + mVariable = itemView.findViewById(R.id.variable); + mIcon = itemView.findViewById(R.id.icon); + mIcon.setOnClickListener(view -> { + int pos = getAdapterPosition(); + WatchingVariable variable = mVariablesAdapter.get(pos); + if (!variable.isPinned()) { + mVariablesAdapter.remove(pos); + } + }); + itemView.setOnClickListener(view -> { + int pos = getAdapterPosition(); + WatchingVariable variable = mVariablesAdapter.get(pos); + showVariable(variable); + }); + } + + @Override + public void bind(WatchingVariable data, int position) { + if (TextUtils.isEmpty(data.getDisplayName())) { + mVariable.setText(""); + } else { + mVariable.setText(String.format("%s = %s", data.getDisplayName(), data.getSingleLineValue())); + } + mIcon.setVisibility(data.isPinned() ? View.INVISIBLE : View.VISIBLE); + } + } + + +} diff --git a/app/src/main/java/org/autojs/autojs/ui/edit/debug/WatchingVariable.java b/app/src/main/java/org/autojs/autojs/ui/edit/debug/WatchingVariable.java new file mode 100644 index 00000000..c11d947b --- /dev/null +++ b/app/src/main/java/org/autojs/autojs/ui/edit/debug/WatchingVariable.java @@ -0,0 +1,53 @@ +package org.autojs.autojs.ui.edit.debug; + +public class WatchingVariable { + + private String mDisplayName; + private String mName; + private final boolean mPinned; + private String mValue; + private String mSingleLineValue; + + public WatchingVariable(String displayName, String name, boolean pinned) { + mDisplayName = displayName; + mName = name; + mPinned = pinned; + } + + public WatchingVariable(String name) { + this(name, name, false); + } + + public boolean isPinned() { + return mPinned; + } + + public String getValue() { + return mValue; + } + + public void setValue(String value) { + mValue = value; + mSingleLineValue = value == null ? null : value.replaceAll("\n", " "); + } + + public String getSingleLineValue() { + return mSingleLineValue; + } + + public void setDisplayName(String displayName) { + mDisplayName = displayName; + } + + public void setName(String name) { + mName = name; + } + + public String getDisplayName() { + return mDisplayName; + } + + public String getName() { + return mName; + } +} diff --git a/app/src/main/java/org/autojs/autojs/ui/edit/editor/CodeEditText.java b/app/src/main/java/org/autojs/autojs/ui/edit/editor/CodeEditText.java index c8e8489a..fab5e057 100644 --- a/app/src/main/java/org/autojs/autojs/ui/edit/editor/CodeEditText.java +++ b/app/src/main/java/org/autojs/autojs/ui/edit/editor/CodeEditText.java @@ -32,18 +32,16 @@ import android.util.Log; import android.util.TimingLogger; import android.view.Gravity; -import org.autojs.autojs.R; import org.autojs.autojs.ui.edit.theme.Theme; import org.autojs.autojs.ui.edit.theme.TokenMapping; -import com.stardust.autojs.execution.ScriptExecution; import com.stardust.util.ClipboardUtil; import com.stardust.util.TextUtils; import org.mozilla.javascript.Token; -import java.util.ArrayList; import java.util.LinkedHashMap; +import java.util.concurrent.CopyOnWriteArrayList; import static org.autojs.autojs.ui.edit.editor.BracketMatching.UNMATCHED_BRACKET; @@ -60,7 +58,7 @@ public class CodeEditText extends AppCompatEditText { // 文字范围 protected HVScrollView mParentScrollView; - private CodeEditor.CursorChangeCallback mCallback; + private final CopyOnWriteArrayList mCursorChangeCallbacks = new CopyOnWriteArrayList<>(); private volatile JavaScriptHighlighter.HighlightTokens mHighlightTokens; private Theme mTheme; private TimingLogger mLogger = new TimingLogger(LOG_TAG, "draw"); @@ -110,6 +108,11 @@ public class CodeEditText extends AppCompatEditText { if (mParentScrollView == null) { mParentScrollView = (HVScrollView) getParent(); } + if (getLayout() == null) { + super.onDraw(canvas); + invalidate(); + return; + } updatePaddingForGutter(); updateLineRangeForDraw(canvas); @@ -266,8 +269,12 @@ public class CodeEditText extends AppCompatEditText { if (line < mFirstLineForDraw || line > mLastLineForDraw || mFirstLineForDraw < 0 || line < 0) { return; } - int lineTop = getLayout().getLineTop(line); - int lineBottom = getLayout().getLineTop(line + 1); + Layout layout = getLayout(); + if(layout == null){ + return; + } + int lineTop = layout.getLineTop(line); + int lineBottom = layout.getLineTop(line + 1); canvas.drawRect(0, lineTop, canvas.getWidth(), lineBottom, paint); } @@ -322,7 +329,8 @@ public class CodeEditText extends AppCompatEditText { protected void onSelectionChanged(int selStart, int selEnd) { //调用父类的onSelectionChanged时会发送一个AccessibilityEvent,当文本过大时造成异常 //super.onSelectionChanged(selStart, selEnd); - if (mCallback == null || selStart != selEnd) { + //父类构造函数会调用onSelectionChanged, 此时mCursorChangeCallbacks还没有初始化 + if (mCursorChangeCallbacks == null || mCursorChangeCallbacks.isEmpty() || selStart != selEnd) { return; } callCursorChangeCallback(getText(), selStart); @@ -365,7 +373,7 @@ public class CodeEditText extends AppCompatEditText { if (text.length() == 0) { return; } - if (mCallback == null) + if (mCursorChangeCallbacks.isEmpty()) return; int lineStart = TextUtils.lastIndexOf(text, '\n', sel - 1) + 1; if (lineStart < 0) { @@ -382,13 +390,21 @@ public class CodeEditText extends AppCompatEditText { return; String line = text.subSequence(lineStart, lineEnd).toString(); int cursor = sel - lineStart; - mCallback.onCursorChange(line, cursor); + for(CodeEditor.CursorChangeCallback callback : mCursorChangeCallbacks){ + callback.onCursorChange(line, cursor); + } } - public void setCursorChangeCallback(CodeEditor.CursorChangeCallback callback) { - mCallback = callback; + public void addCursorChangeCallback(CodeEditor.CursorChangeCallback callback) { + mCursorChangeCallbacks.add(callback); } + public boolean removeCursorChangeCallback(CodeEditor.CursorChangeCallback callback) { + return mCursorChangeCallbacks.remove(callback); + } + + + public void updateHighlightTokens(JavaScriptHighlighter.HighlightTokens highlightTokens) { mHighlightTokens = highlightTokens; postInvalidate(); @@ -427,7 +443,7 @@ public class CodeEditText extends AppCompatEditText { Parcelable superData = bundle.getParcelable("super_data"); mDebuggingLine = bundle.getInt("debugging_line", -1); int[] breakpoints = bundle.getIntArray("breakpoints"); - if(breakpoints != null){ + if (breakpoints != null) { for (int breakpoint : breakpoints) { mBreakpoints.put(breakpoint, new CodeEditor.Breakpoint(breakpoint)); } diff --git a/app/src/main/java/org/autojs/autojs/ui/edit/editor/CodeEditor.java b/app/src/main/java/org/autojs/autojs/ui/edit/editor/CodeEditor.java index 5e7e9520..382fd363 100644 --- a/app/src/main/java/org/autojs/autojs/ui/edit/editor/CodeEditor.java +++ b/app/src/main/java/org/autojs/autojs/ui/edit/editor/CodeEditor.java @@ -176,9 +176,14 @@ public class CodeEditor extends HVScrollView { } public void setReadOnly(boolean readOnly) { - setEnabled(!readOnly); + mCodeEditText.setEnabled(!readOnly); } + public void setRedoUndoEnabled(boolean enabled) { + mTextViewRedoUndo.setEnabled(enabled); + } + + public void setProgress(boolean progress) { if (progress) { if (mProcessDialog != null) { @@ -202,8 +207,12 @@ public class CodeEditor extends HVScrollView { mCodeEditText.setText(text); } - public void setCursorChangeCallback(CursorChangeCallback callback) { - mCodeEditText.setCursorChangeCallback(callback); + public void addCursorChangeCallback(CursorChangeCallback callback) { + mCodeEditText.addCursorChangeCallback(callback); + } + + public boolean removeCursorChangeCallback(CursorChangeCallback callback) { + return mCodeEditText.removeCursorChangeCallback(callback); } @@ -337,7 +346,6 @@ public class CodeEditor extends HVScrollView { } public void setDebuggingLine(int line) { - jumpTo(line, 0); mCodeEditText.setDebuggingLine(line); } @@ -356,6 +364,11 @@ public class CodeEditor extends HVScrollView { addOrRemoveBreakpoint(line); } + public void removeAllBreakpoints(){ + mCodeEditText.getBreakpoints().clear(); + mCodeEditText.invalidate(); + } + @Override protected void onDraw(Canvas canvas) { diff --git a/app/src/main/java/org/autojs/autojs/ui/edit/editor/TextViewRedoUndo.java b/app/src/main/java/org/autojs/autojs/ui/edit/editor/TextViewRedoUndo.java index 8d24fd4e..aa20f7b1 100644 --- a/app/src/main/java/org/autojs/autojs/ui/edit/editor/TextViewRedoUndo.java +++ b/app/src/main/java/org/autojs/autojs/ui/edit/editor/TextViewRedoUndo.java @@ -42,6 +42,7 @@ public class TextViewRedoUndo { private boolean flag = false; private int mInitialHistoryStackSize; + private boolean mEnabled = true; public TextViewRedoUndo(@NonNull EditText editText) { this.editable = editText.getText(); @@ -156,6 +157,14 @@ public class TextViewRedoUndo { mInitialHistoryStackSize = history.size(); } + public void setEnabled(boolean enabled) { + mEnabled = enabled; + } + + public boolean isEnabled() { + return mEnabled; + } + private class Watcher implements TextWatcher { /** @@ -168,6 +177,9 @@ public class TextViewRedoUndo { */ @Override public final void beforeTextChanged(CharSequence s, int start, int count, int after) { + if (!editText.isEnabled() || !mEnabled) { + return; + } if (flag) return; int end = start + count; if (end > start && end <= s.length()) { @@ -201,6 +213,9 @@ public class TextViewRedoUndo { */ @Override public final void onTextChanged(CharSequence s, int start, int before, int count) { + if (!editText.isEnabled() || !mEnabled) { + return; + } if (flag) return; int end = start + count; if (end > start) { @@ -223,6 +238,9 @@ public class TextViewRedoUndo { @Override public final void afterTextChanged(Editable s) { + if (!editText.isEnabled() || !mEnabled) { + return; + } if (flag) return; if (s != editable) { editable = s; diff --git a/app/src/main/java/org/autojs/autojs/ui/edit/toolbar/DebugToolbarFragment.java b/app/src/main/java/org/autojs/autojs/ui/edit/toolbar/DebugToolbarFragment.java index 21feb219..1b5e0324 100644 --- a/app/src/main/java/org/autojs/autojs/ui/edit/toolbar/DebugToolbarFragment.java +++ b/app/src/main/java/org/autojs/autojs/ui/edit/toolbar/DebugToolbarFragment.java @@ -4,20 +4,28 @@ import android.os.Bundle; import android.os.Handler; import android.os.Looper; import android.support.annotation.Nullable; +import android.support.v7.widget.RecyclerView; +import android.text.TextUtils; import android.util.Log; import android.view.View; +import android.widget.Toast; import com.stardust.autojs.engine.RhinoJavaScriptEngine; import com.stardust.autojs.execution.ScriptExecution; import com.stardust.autojs.rhino.debug.Dim; import com.stardust.autojs.rhino.debug.DebugCallback; +import com.stardust.autojs.runtime.exception.ScriptInterruptedException; +import com.stardust.pio.PFiles; import org.androidannotations.annotations.Click; import org.androidannotations.annotations.EFragment; import org.autojs.autojs.R; import org.autojs.autojs.autojs.AutoJs; import org.autojs.autojs.ui.edit.EditorView; +import org.autojs.autojs.ui.edit.debug.CodeEvaluator; +import org.autojs.autojs.ui.edit.debug.DebugBar; +import org.autojs.autojs.ui.edit.debug.WatchingVariable; import org.autojs.autojs.ui.edit.editor.CodeEditor; import org.mozilla.javascript.ContextFactory; @@ -25,12 +33,23 @@ import java.util.Arrays; import java.util.List; @EFragment(R.layout.fragment_debug_toolbar) -public class DebugToolbarFragment extends ToolbarFragment implements DebugCallback { +public class DebugToolbarFragment extends ToolbarFragment implements DebugCallback, CodeEditor.CursorChangeCallback, CodeEvaluator { private static final String LOG_TAG = "DebugToolbarFragment"; private Dim mDim; private EditorView mEditorView; private Handler mHandler; + private boolean mSkipOtherFileBreakpoint = false; + private String mCurrentEditorSourceUrl; + private String mInitialEditorSourceUrl; + private String mInitialEditorSource; + private boolean mCursorChangeFromUser = true; + private final RecyclerView.AdapterDataObserver mVariableChangeObserver = new RecyclerView.AdapterDataObserver() { + @Override + public void onItemRangeInserted(int positionStart, int itemCount) { + updateWatchingVariables(positionStart, positionStart + itemCount); + } + }; public DebugToolbarFragment() { Log.d(LOG_TAG, "DebugToolbarFragment()"); @@ -46,37 +65,64 @@ public class DebugToolbarFragment extends ToolbarFragment implements DebugCallba public void onViewCreated(View view, @Nullable Bundle savedInstanceState) { super.onViewCreated(view, savedInstanceState); mEditorView = findEditorView(view); - ScriptExecution scriptExecution = mEditorView.getScriptExecution(); - if (scriptExecution != null) { - mDim = (Dim) scriptExecution.getEngine().getTag(Dim.TAG); - } - if (mDim == null) { - mDim = new Dim(); - mDim.setBreak(); - mDim.setBreakOnExceptions(true); - mDim.attachTo(AutoJs.getInstance().getScriptEngineService(), ContextFactory.getGlobal()); - mDim.setGuiCallback(this); - setInterrupted(false); - mEditorView.run(); - } else { - mDim.setGuiCallback(this); - } + mDim = createDim(); + setInterrupted(false); + mSkipOtherFileBreakpoint = true; + mCurrentEditorSourceUrl = mInitialEditorSourceUrl = mEditorView.getFile().toString(); + mInitialEditorSource = mEditorView.getEditor().getText(); + setupEditor(); + mEditorView.run(false); Log.d(LOG_TAG, "onViewCreated"); } + private void setupEditor() { + CodeEditor editor = mEditorView.getEditor(); + editor.setRedoUndoEnabled(false); + editor.addCursorChangeCallback(this); + DebugBar debugBar = mEditorView.getDebugBar(); + debugBar.registerVariableChangeObserver(mVariableChangeObserver); + debugBar.setCodeEvaluator(this); + + } + + private Dim createDim() { + Dim dim = new Dim(); + dim.setBreak(); + dim.setBreakOnExceptions(true); + dim.attachTo(AutoJs.getInstance().getScriptEngineService(), ContextFactory.getGlobal()); + dim.setGuiCallback(this); + return dim; + } + private void setInterrupted(boolean interrupted) { setMenuItemStatus(R.id.step_into, interrupted); setMenuItemStatus(R.id.step_over, interrupted); setMenuItemStatus(R.id.step_out, interrupted); setMenuItemStatus(R.id.resume_script, interrupted); - if (!interrupted) { + if (!interrupted && mEditorView != null) { mEditorView.getEditor().setDebuggingLine(-1); } } public void detachDebugger() { + if (!mDim.isAttached()) { + return; + } mDim.detach(); mDim.setGuiCallback(null); + if (mEditorView == null) { + return; + } + CodeEditor editor = mEditorView.getEditor(); + editor.removeCursorChangeCallback(this); + editor.setRedoUndoEnabled(true); + if (!TextUtils.equals(mInitialEditorSourceUrl, mCurrentEditorSourceUrl)) { + editor.setText(mInitialEditorSource); + } + DebugBar debugBar = mEditorView.getDebugBar(); + debugBar.setTitle(null); + debugBar.setCodeEvaluator(null); + debugBar.unregisterVariableChangeObserver(mVariableChangeObserver); } @Click(R.id.step_over) @@ -125,18 +171,72 @@ public class DebugToolbarFragment extends ToolbarFragment implements DebugCallba } @Override - public void enterInterrupt(Dim.StackFrame stackFrame, String threadName, String s1) { + public void enterInterrupt(Dim.StackFrame stackFrame, String threadName, String message) { Log.d(LOG_TAG, "enterInterrupt: threadName = " + threadName + ", url = " + stackFrame.getUrl() + ", line = " + stackFrame.getLineNumber()); - if (stackFrame.getUrl().equals(mEditorView.getFile().toString())) { - final int line = stackFrame.getLineNumber() - 1; - mHandler.post(() -> { - mEditorView.getEditor().setDebuggingLine(line); - setInterrupted(true); - }); - - } else { + //刚启动调试时会在init脚本的第一行自动停下,此时应该让脚本继续运行 + if (mSkipOtherFileBreakpoint && !stackFrame.getUrl().equals(mInitialEditorSourceUrl) && message == null) { mHandler.post(this::resumeScript); + return; } + mSkipOtherFileBreakpoint = false; + showDebuggingLineOnEditor(stackFrame, message); + mHandler.post(this::updateWatchingVariables); + } + + private void updateWatchingVariables() { + updateWatchingVariables(0, mEditorView.getDebugBar().getWatchingVariables().size()); + } + + private void updateWatchingVariables(int start, int end) { + if (!mDim.isAttached()) { + return; + } + DebugBar debugBar = mEditorView.getDebugBar(); + List variables = debugBar.getWatchingVariables(); + for (int i = start; i < end; i++) { + WatchingVariable variable = variables.get(i); + String value = eval(variable.getName()); + variable.setValue(value); + } + debugBar.refresh(start, end - start); + } + + public String eval(String expr) { + if (expr == null || !mDim.isAttached() || !mDim.stringIsCompilableUnit(expr)) { + return null; + } + mDim.contextSwitch(0); + return mDim.eval(expr); + } + + private void showDebuggingLineOnEditor(Dim.StackFrame stackFrame, String message) { + //如果调试进入到其他脚本(例如模块脚本),则改变当前编辑器的文本为自动调试的脚本的代码 + String source; + //标记是否需要更改编辑器文本 + boolean shouldChangeText = !stackFrame.getUrl().equals(mCurrentEditorSourceUrl); + if (shouldChangeText) { + source = stackFrame.sourceInfo().source(); + } else { + source = null; + } + mCurrentEditorSourceUrl = stackFrame.getUrl(); + final int line = stackFrame.getLineNumber() - 1; + mHandler.post(() -> { + if (mEditorView == null) { + return; + } + if (shouldChangeText) { + mEditorView.getEditor().setText(source); + } + mCursorChangeFromUser = false; + mEditorView.getEditor().setDebuggingLine(line); + mEditorView.getEditor().jumpTo(line, 0); + mEditorView.getDebugBar().setTitle(PFiles.getName(mCurrentEditorSourceUrl)); + setInterrupted(true); + if (message != null && !message.equals(ScriptInterruptedException.class.getName())) { + Toast.makeText(mEditorView.getContext(), message, Toast.LENGTH_LONG).show(); + } + }); } @Override @@ -155,9 +255,54 @@ public class DebugToolbarFragment extends ToolbarFragment implements DebugCallba } + @Override + public void onCursorChange(String line, int ch) { + if (ch == 0 && !mCursorChangeFromUser) { + mCursorChangeFromUser = true; + return; + } + mCursorChangeFromUser = true; + if (!mDim.isAttached()) { + return; + } + String variable = findVariableOnCursor(line, ch); + Log.d(LOG_TAG, "onCursorChange: variable = " + variable + ", ch = " + ch + ", line = " + line); + String value = eval(variable); + mEditorView.getDebugBar().updateCurrentVariable(variable, value); + } + + private String findVariableOnCursor(String line, int ch) { + int end; + for (end = ch; end < line.length(); end++) { + if (!isIdentifierChar(line.charAt(end))) { + break; + } + } + int start; + for (start = Math.min(ch - 1, line.length() - 1); start >= 0; start--) { + if (!isIdentifierChar(line.charAt(start))) { + break; + } + } + start++; + if (start < end && start < line.length() && start >= 0) { + return line.substring(start, end); + } + return null; + } + + private boolean isIdentifierChar(char c) { + return Character.isDigit(c) || Character.isLetter(c) || c == '.' || c == '_'; + } + @Override public List getMenuItemIds() { return Arrays.asList(R.id.step_over, R.id.step_into, R.id.step_out, R.id.resume_script, R.id.stop_script); } + @Override + public void onDestroy() { + super.onDestroy(); + detachDebugger(); + } } diff --git a/app/src/main/java/org/autojs/autojs/ui/edit/toolbar/NormalToolbarFragment.java b/app/src/main/java/org/autojs/autojs/ui/edit/toolbar/NormalToolbarFragment.java index 1f718d2f..64f2ecc8 100644 --- a/app/src/main/java/org/autojs/autojs/ui/edit/toolbar/NormalToolbarFragment.java +++ b/app/src/main/java/org/autojs/autojs/ui/edit/toolbar/NormalToolbarFragment.java @@ -1,8 +1,5 @@ package org.autojs.autojs.ui.edit.toolbar; -import android.support.v4.app.Fragment; - -import org.androidannotations.annotations.Click; import org.androidannotations.annotations.EFragment; import org.autojs.autojs.R; @@ -12,7 +9,6 @@ import java.util.List; @EFragment(R.layout.fragment_normal_toolbar) public class NormalToolbarFragment extends ToolbarFragment { - @Override public List getMenuItemIds() { return Arrays.asList(R.id.run, R.id.undo, R.id.redo, R.id.save); diff --git a/app/src/main/java/org/autojs/autojs/ui/edit/toolbar/ToolbarFragment.java b/app/src/main/java/org/autojs/autojs/ui/edit/toolbar/ToolbarFragment.java index aed9a309..c531971f 100644 --- a/app/src/main/java/org/autojs/autojs/ui/edit/toolbar/ToolbarFragment.java +++ b/app/src/main/java/org/autojs/autojs/ui/edit/toolbar/ToolbarFragment.java @@ -11,19 +11,29 @@ import org.autojs.autojs.ui.edit.EditorView; import java.util.List; -public abstract class ToolbarFragment extends Fragment implements View.OnClickListener { +public abstract class ToolbarFragment extends Fragment implements View.OnClickListener, View.OnLongClickListener { + public interface OnMenuItemClickListener { void onToolbarMenuItemClick(int id); } + public interface OnMenuItemLongClickListener { + boolean onToolbarMenuItemLongClick(int id); + } + private OnMenuItemClickListener mOnMenuItemClickListener; + private OnMenuItemLongClickListener mOnMenuItemLongClickListener; private List mMenuItemIds; public void setOnMenuItemClickListener(OnMenuItemClickListener listener) { mOnMenuItemClickListener = listener; } + public void setOnMenuItemLongClickListener(OnMenuItemLongClickListener onMenuItemLongClickListener) { + mOnMenuItemLongClickListener = onMenuItemLongClickListener; + } + public abstract List getMenuItemIds(); @Override @@ -54,6 +64,7 @@ public abstract class ToolbarFragment extends Fragment implements View.OnClickLi for (int id : mMenuItemIds) { View view = rootView.findViewById(id); view.setOnClickListener(this); + view.setOnLongClickListener(this); view.setEnabled(editorView.getMenuItemStatus(id, view.isEnabled())); } } @@ -66,6 +77,13 @@ public abstract class ToolbarFragment extends Fragment implements View.OnClickLi } } + + @Override + public boolean onLongClick(View v) { + return mOnMenuItemLongClickListener != null && + mOnMenuItemLongClickListener.onToolbarMenuItemLongClick(v.getId()); + } + public void setMenuItemStatus(int id, boolean enabled) { if (mMenuItemIds == null) { mMenuItemIds = getMenuItemIds(); diff --git a/app/src/main/java/org/autojs/autojs/ui/main/drawer/DrawerFragment.java b/app/src/main/java/org/autojs/autojs/ui/main/drawer/DrawerFragment.java index 595de0a2..d6c92d15 100644 --- a/app/src/main/java/org/autojs/autojs/ui/main/drawer/DrawerFragment.java +++ b/app/src/main/java/org/autojs/autojs/ui/main/drawer/DrawerFragment.java @@ -89,7 +89,7 @@ public class DrawerFragment extends android.support.v4.app.Fragment { RecyclerView mDrawerMenu; - private DrawerMenuItem mConnectionItem = new DrawerMenuItem(R.drawable.ic_debug, R.string.debug, 0, this::connectOrDisconnectToRemote); + private DrawerMenuItem mConnectionItem = new DrawerMenuItem(R.drawable.ic_connect_to_pc, R.string.debug, 0, this::connectOrDisconnectToRemote); private DrawerMenuItem mAccessibilityServiceItem = new DrawerMenuItem(R.drawable.ic_service_green, R.string.text_accessibility_service, 0, this::enableOrDisableAccessibilityService); private DrawerMenuItem mStableModeItem = new DrawerMenuItem(R.drawable.ic_stable, R.string.text_stable_mode, R.string.key_stable_mode, null) { @Override diff --git a/app/src/main/java/org/autojs/autojs/ui/widget/AutoAdapter.java b/app/src/main/java/org/autojs/autojs/ui/widget/AutoAdapter.java index 1cef1024..400e225b 100644 --- a/app/src/main/java/org/autojs/autojs/ui/widget/AutoAdapter.java +++ b/app/src/main/java/org/autojs/autojs/ui/widget/AutoAdapter.java @@ -14,12 +14,16 @@ import java.util.List; public class AutoAdapter
extends RecyclerView.Adapter> { private ViewHolderSupplier> mViewHolderSupplier; - private List
mList = new ArrayList<>(); + private final List
mData = new ArrayList<>(); public AutoAdapter(ViewHolderSupplier> viewHolderSupplier) { mViewHolderSupplier = viewHolderSupplier; } + public AutoAdapter(ViewHolderSupplier.ViewHolderCreator> viewHolderCreator, int layoutRes) { + mViewHolderSupplier = ViewHolderSupplier.of(viewHolderCreator, layoutRes); + } + @Override public BindableViewHolder
onCreateViewHolder(ViewGroup parent, int viewType) { @@ -28,36 +32,48 @@ public class AutoAdapter
extends RecyclerView.Adapter @Override public void onBindViewHolder(BindableViewHolder
holder, int position) { - holder.bind(mList.get(position), position); + holder.bind(mData.get(position), position); } @Override public int getItemCount() { - return mList.size(); + return mData.size(); } public void remove(DT data) { - int pos = mList.indexOf(data); + int pos = mData.indexOf(data); if (pos < 0) return; - mList.remove(pos); + mData.remove(pos); notifyItemRemoved(pos); } public void remove(int index) { - mList.remove(index); + mData.remove(index); notifyItemRemoved(index); } public void addAll(Collection c) { - mList.addAll(c); - notifyItemRangeInserted(mList.size() - c.size() - 1, mList.size() - 1); + mData.addAll(c); + notifyItemRangeInserted(mData.size() - c.size() - 1, mData.size() - 1); + } + + public DT get(int index){ + return mData.get(index); } public void setData(Collection c) { - mList.clear(); - mList.addAll(c); + mData.clear(); + mData.addAll(c); notifyDataSetChanged(); } + public void add(DT item) { + mData.add(item); + notifyItemInserted(mData.size() - 1); + } + + public List
getData() { + return mData; + } } diff --git a/app/src/main/java/org/autojs/autojs/ui/widget/ViewHolderSupplier.java b/app/src/main/java/org/autojs/autojs/ui/widget/ViewHolderSupplier.java index df55553d..6178ac27 100644 --- a/app/src/main/java/org/autojs/autojs/ui/widget/ViewHolderSupplier.java +++ b/app/src/main/java/org/autojs/autojs/ui/widget/ViewHolderSupplier.java @@ -11,22 +11,30 @@ import java.lang.reflect.Constructor; * Created by Stardust on 2017/4/8. */ -public abstract class ViewHolderSupplier { +public interface ViewHolderSupplier { - public abstract VH createViewHolder(ViewGroup parent, int viewType); + VH createViewHolder(ViewGroup parent, int viewType); - public static ViewHolderSupplier of(final Class c, final int layoutRes) { - return new ViewHolderSupplier() { - @Override - public VH createViewHolder(ViewGroup parent, int viewType) { - try { - Constructor constructor = c.getConstructor(View.class); - return constructor.newInstance(LayoutInflater.from(parent.getContext()).inflate(layoutRes, parent, false)); - } catch (Exception e) { - throw new RuntimeException(e); - } + interface ViewHolderCreator { + VH createViewHolder(View itemView); + } + + static ViewHolderSupplier of(final Class c, final int layoutRes) { + return (parent, viewType) -> { + try { + Constructor constructor = c.getConstructor(View.class); + return constructor.newInstance(LayoutInflater.from(parent.getContext()).inflate(layoutRes, parent, false)); + } catch (Exception e) { + throw new RuntimeException(e); } }; } + static ViewHolderSupplier of(ViewHolderCreator creator, final int layoutRes) { + return (parent, viewType) -> + creator.createViewHolder(LayoutInflater.from(parent.getContext()).inflate(layoutRes, parent, false) + ); + } + + } diff --git a/app/src/main/res/drawable-xhdpi/ic_connect_to_pc.png b/app/src/main/res/drawable-xhdpi/ic_connect_to_pc.png new file mode 100644 index 0000000000000000000000000000000000000000..c766543b450800aeaa8eb94a35d6ccaed280bb9f GIT binary patch literal 3196 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 I*o5W(A6Pz@p#T5? literal 0 HcmV?d00001 diff --git a/app/src/main/res/drawable-xhdpi/ic_debug.png b/app/src/main/res/drawable-xhdpi/ic_debug.png index c766543b450800aeaa8eb94a35d6ccaed280bb9f..1ae9a64d7369dbc72b00d69127acf9923f311167 100644 GIT binary patch delta 2493 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 Hu0mjfbjz)1 literal 3196 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 I*o5W(A6Pz@p#T5? diff --git a/app/src/main/res/drawable/ic_debug.png b/app/src/main/res/drawable/ic_connect_to_pc.png similarity index 100% rename from app/src/main/res/drawable/ic_debug.png rename to app/src/main/res/drawable/ic_connect_to_pc.png diff --git a/app/src/main/res/drawable/ic_script.png b/app/src/main/res/drawable/ic_script.png new file mode 100644 index 0000000000000000000000000000000000000000..47fdf3c2ef8c33d884e6fae25b52da7dba63d4a8 GIT binary patch literal 3072 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 literal 0 HcmV?d00001 diff --git a/app/src/main/res/layout/debug_bar.xml b/app/src/main/res/layout/debug_bar.xml new file mode 100644 index 00000000..66b9f8f1 --- /dev/null +++ b/app/src/main/res/layout/debug_bar.xml @@ -0,0 +1,54 @@ + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/dialog_code_evaluate.xml b/app/src/main/res/layout/dialog_code_evaluate.xml new file mode 100644 index 00000000..4421dc07 --- /dev/null +++ b/app/src/main/res/layout/dialog_code_evaluate.xml @@ -0,0 +1,38 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/editor_view.xml b/app/src/main/res/layout/editor_view.xml index 29112e7c..09081cb3 100644 --- a/app/src/main/res/layout/editor_view.xml +++ b/app/src/main/res/layout/editor_view.xml @@ -88,6 +88,13 @@ android:layout_height="match_parent" android:visibility="gone"/> + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/menu/menu_editor.xml b/app/src/main/res/menu/menu_editor.xml index bc7ae83f..744e95bc 100644 --- a/app/src/main/res/menu/menu_editor.xml +++ b/app/src/main/res/menu/menu_editor.xml @@ -94,6 +94,11 @@ android:id="@+id/action_launch_debugger" android:title="@string/text_launch_debugger" app:showAsAction="never"/> + + diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index fff2e2fc..5ab6524d 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -367,4 +367,15 @@ 单步 继续 停止 + 增加监视的变量或表达式 + 变量或表达式 + 变量 + 删除所有断点 + 长按\"运行\"图标也可以启动调试 + 调试 [%s] + 复制值 + 执行代码 + 代码 + 结果 + 关闭 diff --git a/autojs/src/main/assets/modules/object-observe-lite.min.js b/autojs/src/main/assets/modules/object-observe-lite.min.js index 61a22aee..1e1a42d9 100644 --- a/autojs/src/main/assets/modules/object-observe-lite.min.js +++ b/autojs/src/main/assets/modules/object-observe-lite.min.js @@ -1,3 +1,3 @@ module.exports = function(){ - Object.observe||function(e,t,n,r){"use strict";var o,i,c=["add","update","delete","reconfigure","setPrototype","preventExtensions"],a=t.isArray||function(e){return function(t){return"[object Array]"===e.call(t)}}(e.prototype.toString),f=t.prototype.indexOf?t.indexOf||function(e,n,r){return t.prototype.indexOf.call(e,n,r)}:function(e,t,n){for(var r=n||0;r-1},get:function(n){return t[f(e,n)]},set:function(n,r){var o=f(e,n);-1===o?(e.push(n),t.push(r),this.size++):t[o]=r},"delete":function(n){var r=f(e,n);r>-1&&(e.splice(r,1),t.splice(r,1),this.size--)},forEach:function(n){for(var r=0;r-1&&n.splice(o,1);return n})}return t}():function(t){var n,r,o=[];if("hasOwnProperty"in t)for(n in t)t.hasOwnProperty(n)&&o.push(n);else{r=e.hasOwnProperty;for(n in t)r.call(t,n)&&o.push(n)}return a(t)&&o.push("length"),o},p=n.requestAnimationFrame||n.webkitRequestAnimationFrame||function(){var e=+new Date,t=e;return function(n){return setTimeout(function(){n((t=+new Date)-e)},17)}}(),l=function(e,t,n){var r=o.get(e);r?(v(r,e),g(e,r,t,n)):(r=h(e),g(e,r,t,n),1===o.size&&p(d))},h=function(e,t){for(var n=u(e),r=[],i=0,t={handlers:s(),properties:n,values:r,notifier:b(e,t)};i-1&&t.changeRecords.push(n)})};o=s(),i=s(),e.observe=function(t,n,o){if(!t||"object"!=typeof t&&"function"!=typeof t)throw new TypeError("Object.observe cannot observe non-object");if("function"!=typeof n)throw new TypeError("Object.observe cannot deliver to non-function");if(e.isFrozen&&e.isFrozen(n))throw new TypeError("Object.observe cannot deliver to a frozen function object");if(o===r)o=c;else if(!o||"object"!=typeof o)throw new TypeError("Third argument to Object.observe must be an array of strings.");return l(t,n,o),t},e.unobserve=function(e,t){if(null===e||"object"!=typeof e&&"function"!=typeof e)throw new TypeError("Object.unobserve cannot unobserve non-object");if("function"!=typeof t)throw new TypeError("Object.unobserve cannot deliver to non-function");var n,r=i.get(t);return r&&(n=r.observed.get(e))&&(r.observed.forEach(function(e,t){v(e.data,t)}),p(function(){y(r,t)}),1===r.observed.size&&r.observed.has(e)?i["delete"](t):r.observed["delete"](e),1===n.data.handlers.size?o["delete"](e):n.data.handlers["delete"](t)),e},e.getNotifier=function(t){if(null===t||"object"!=typeof t&&"function"!=typeof t)throw new TypeError("Object.getNotifier cannot getNotifier non-object");return e.isFrozen&&e.isFrozen(t)?null:b(t)},e.deliverChangeRecords=function(e){if("function"!=typeof e)throw new TypeError("Object.deliverChangeRecords cannot deliver to non-function");var t=i.get(e);t&&(t.observed.forEach(function(e,t){v(e.data,t)}),y(t,e))}}(Object,Array,this); + Object.observe||function(e,t,n,r){var o,i,c=["add","update","delete","reconfigure","setPrototype","preventExtensions"],a=t.isArray||function(e){return function(t){return"[object Array]"===e.call(t)}}(e.prototype.toString),f=t.prototype.indexOf?t.indexOf||function(e,n,r){return t.prototype.indexOf.call(e,n,r)}:function(e,t,n){for(var r=n||0;r-1},get:function(n){return t[f(e,n)]},set:function(n,r){var o=f(e,n);-1===o?(e.push(n),t.push(r),this.size++):t[o]=r},"delete":function(n){var r=f(e,n);r>-1&&(e.splice(r,1),t.splice(r,1),this.size--)},forEach:function(n){for(var r=0;r-1&&n.splice(o,1);return n})}return t}():function(t){var n,r,o=[];if("hasOwnProperty"in t)for(n in t)t.hasOwnProperty(n)&&o.push(n);else{r=e.hasOwnProperty;for(n in t)r.call(t,n)&&o.push(n)}return a(t)&&o.push("length"),o},p=n.requestAnimationFrame||n.webkitRequestAnimationFrame||function(){var e=+new Date,t=e;return function(n){return setTimeout(function(){n((t=+new Date)-e)},17)}}(),l=function(e,t,n){var r=o.get(e);r?(v(r,e),g(e,r,t,n)):(r=h(e),g(e,r,t,n),1===o.size&&p(d))},h=function(e,t){for(var n=u(e),r=[],i=0,t={handlers:s(),properties:n,values:r,notifier:b(e,t)};i-1&&t.changeRecords.push(n)})};o=s(),i=s(),e.observe=function(t,n,o){if(!t||"object"!=typeof t&&"function"!=typeof t)throw new TypeError("Object.observe cannot observe non-object");if("function"!=typeof n)throw new TypeError("Object.observe cannot deliver to non-function");if(e.isFrozen&&e.isFrozen(n))throw new TypeError("Object.observe cannot deliver to a frozen function object");if(o===r)o=c;else if(!o||"object"!=typeof o)throw new TypeError("Third argument to Object.observe must be an array of strings.");return l(t,n,o),t},e.unobserve=function(e,t){if(null===e||"object"!=typeof e&&"function"!=typeof e)throw new TypeError("Object.unobserve cannot unobserve non-object");if("function"!=typeof t)throw new TypeError("Object.unobserve cannot deliver to non-function");var n,r=i.get(t);return r&&(n=r.observed.get(e))&&(r.observed.forEach(function(e,t){v(e.data,t)}),p(function(){y(r,t)}),1===r.observed.size&&r.observed.has(e)?i["delete"](t):r.observed["delete"](e),1===n.data.handlers.size?o["delete"](e):n.data.handlers["delete"](t)),e},e.getNotifier=function(t){if(null===t||"object"!=typeof t&&"function"!=typeof t)throw new TypeError("Object.getNotifier cannot getNotifier non-object");return e.isFrozen&&e.isFrozen(t)?null:b(t)},e.deliverChangeRecords=function(e){if("function"!=typeof e)throw new TypeError("Object.deliverChangeRecords cannot deliver to non-function");var t=i.get(e);t&&(t.observed.forEach(function(e,t){v(e.data,t)}),y(t,e))}}(Object,Array,this); } \ No newline at end of file diff --git a/autojs/src/main/java/com/stardust/autojs/rhino/debug/Dim.java b/autojs/src/main/java/com/stardust/autojs/rhino/debug/Dim.java index ef5bed5d..95722e05 100644 --- a/autojs/src/main/java/com/stardust/autojs/rhino/debug/Dim.java +++ b/autojs/src/main/java/com/stardust/autojs/rhino/debug/Dim.java @@ -78,7 +78,7 @@ public class Dim { /** * The ContextFactory to listen to for debugging information. */ - private ContextFactory contextFactory; + private volatile ContextFactory contextFactory; private ScriptEngineService scriptEngineService; @@ -222,7 +222,7 @@ public class Dim { detach(); this.contextFactory = factory; this.scriptEngineService = scriptEngineService; - this.listener = new DimIProxy(this, IPROXY_LISTEN); + this.listener = new DimIProxy(IPROXY_LISTEN); scriptEngineService.registerEngineLifecycleCallback(this.listener); } @@ -517,6 +517,10 @@ public class Dim { } } + public boolean isAttached() { + return contextFactory != null && scriptEngineService != null; + } + /** * Returns the current ContextData object. */ @@ -585,7 +589,7 @@ public class Dim { * Compiles the given script. */ public void compileScript(String url, String text) { - DimIProxy action = new DimIProxy(this, IPROXY_COMPILE_SCRIPT); + DimIProxy action = new DimIProxy(IPROXY_COMPILE_SCRIPT); action.url = url; action.text = text; action.withContext(); @@ -595,7 +599,7 @@ public class Dim { * Evaluates the given script. */ public void evalScript(final String url, final String text) { - DimIProxy action = new DimIProxy(this, IPROXY_EVAL_SCRIPT); + DimIProxy action = new DimIProxy(IPROXY_EVAL_SCRIPT); action.url = url; action.text = text; action.withContext(); @@ -605,7 +609,7 @@ public class Dim { * Converts the given script object to a string. */ public String objectToString(Object object) { - DimIProxy action = new DimIProxy(this, IPROXY_OBJECT_TO_STRING); + DimIProxy action = new DimIProxy(IPROXY_OBJECT_TO_STRING); action.object = object; action.withContext(); return action.stringResult; @@ -615,7 +619,7 @@ public class Dim { * Returns whether the given string is syntactically valid script. */ public boolean stringIsCompilableUnit(String str) { - DimIProxy action = new DimIProxy(this, IPROXY_STRING_IS_COMPILABLE); + DimIProxy action = new DimIProxy(IPROXY_STRING_IS_COMPILABLE); action.text = str; action.withContext(); return action.booleanResult; @@ -625,7 +629,7 @@ public class Dim { * Returns the value of a property on the given script object. */ public Object getObjectProperty(Object object, Object id) { - DimIProxy action = new DimIProxy(this, IPROXY_OBJECT_PROPERTY); + DimIProxy action = new DimIProxy(IPROXY_OBJECT_PROPERTY); action.object = object; action.id = id; action.withContext(); @@ -636,7 +640,7 @@ public class Dim { * Returns an array of the property names on the given script object. */ public Object[] getObjectIds(Object object) { - DimIProxy action = new DimIProxy(this, IPROXY_OBJECT_IDS); + DimIProxy action = new DimIProxy(IPROXY_OBJECT_IDS); action.object = object; action.withContext(); return action.objectArrayResult; @@ -894,11 +898,6 @@ public class Dim { private class DimIProxy implements ContextAction, ScriptEngineManager.EngineLifecycleCallback, Debugger { - /** - * The debugger. - */ - private Dim dim; - /** * The interface implementation type. One of the IPROXY_* constants * defined in {@link Dim}. @@ -948,8 +947,7 @@ public class Dim { /** * Creates a new DimIProxy. */ - private DimIProxy(Dim dim, int type) { - this.dim = dim; + private DimIProxy(int type) { this.type = type; } @@ -966,8 +964,8 @@ public class Dim { case IPROXY_EVAL_SCRIPT: { Scriptable scope = null; - if (dim.scopeProvider != null) { - scope = dim.scopeProvider.getScope(); + if (scopeProvider != null) { + scope = scopeProvider.getScope(); } if (scope == null) { scope = new ImporterTopLevel(cx); @@ -993,11 +991,11 @@ public class Dim { break; case IPROXY_OBJECT_PROPERTY: - objectResult = dim.getObjectPropertyImpl(cx, object, id); + objectResult = getObjectPropertyImpl(cx, object, id); break; case IPROXY_OBJECT_IDS: - objectArrayResult = dim.getObjectIdsImpl(cx, object); + objectArrayResult = getObjectIdsImpl(cx, object); break; default: @@ -1011,7 +1009,7 @@ public class Dim { * {@link ContextFactory}. */ private void withContext() { - dim.contextFactory.call(this); + contextFactory.call(this); } @Override @@ -1024,7 +1022,7 @@ public class Dim { Context cx = ((RhinoJavaScriptEngine) engine).getContext(); ContextData contextData = new ContextData(); - Debugger debugger = new DimIProxy(dim, IPROXY_DEBUG); + Debugger debugger = new DimIProxy(IPROXY_DEBUG); cx.setDebugger(debugger, contextData); cx.setGeneratingDebug(true); cx.setOptimizationLevel(-1); @@ -1044,12 +1042,12 @@ public class Dim { public DebugFrame getFrame(Context cx, DebuggableScript fnOrScript) { if (type != IPROXY_DEBUG) Kit.codeBug(); - FunctionSource item = dim.getFunctionSource(fnOrScript); + FunctionSource item = getFunctionSource(fnOrScript); if (item == null) { // Can not debug if source is not available return null; } - return new StackFrame(cx, dim, item); + return new StackFrame(cx, Dim.this, item); } /** @@ -1063,7 +1061,7 @@ public class Dim { if (!fnOrScript.isTopLevel()) { return; } - dim.registerTopScript(fnOrScript, source); + registerTopScript(fnOrScript, source); } }