diff --git a/app/src/main/assets/editor/codemirror/addon/search/search.js b/app/src/main/assets/editor/codemirror/addon/search/search.js index 4059ccdd..e41a08d9 100644 --- a/app/src/main/assets/editor/codemirror/addon/search/search.js +++ b/app/src/main/assets/editor/codemirror/addon/search/search.js @@ -166,10 +166,13 @@ function findNext(cm, rev, callback) {cm.operation(function() { var state = getSearchState(cm); - var cursor = getSearchCursor(cm, state.query, rev ? state.posFrom : state.posTo); - if (!cursor.find(rev)) { - cursor = getSearchCursor(cm, state.query, rev ? CodeMirror.Pos(cm.lastLine()) : CodeMirror.Pos(cm.firstLine(), 0)); - if (!cursor.find(rev)) return; + var query = parseQuery(state.query); + var cursor = getSearchCursor(cm, query, rev ? state.posFrom : state.posTo); + var match = cursor.find(rev); + if (!match) { + cursor = getSearchCursor(cm, query, rev ? CodeMirror.Pos(cm.lastLine()) : CodeMirror.Pos(cm.firstLine(), 0)); + match = cursor.find(rev); + if (!match) return; } cm.setSelection(cursor.from(), cursor.to()); cm.scrollIntoView({from: cursor.from(), to: cursor.to()}, 20); @@ -202,42 +205,12 @@ }); } - function replace(cm, all) { - if (cm.getOption("readOnly")) return; - var query = cm.getSelection() || getSearchState(cm).lastQuery; - var dialogText = '' + (all ? 'Replace all:' : 'Replace:') + ''; - dialog(cm, dialogText + replaceQueryDialog, dialogText, query, function(query) { - if (!query) return; - query = parseQuery(query); - dialog(cm, replacementQueryDialog, "Replace with:", "", function(text) { - text = parseString(text) - if (all) { - replaceAll(cm, query, text) - } else { - clearSearch(cm); - var cursor = getSearchCursor(cm, query, cm.getCursor("from")); - var advance = function() { - var start = cursor.from(), match; - if (!(match = cursor.findNext())) { - cursor = getSearchCursor(cm, query); - if (!(match = cursor.findNext()) || - (start && cursor.from().line == start.line && cursor.from().ch == start.ch)) return; - } - cm.setSelection(cursor.from(), cursor.to()); - cm.scrollIntoView({from: cursor.from(), to: cursor.to()}); - confirmDialog(cm, doReplaceConfirm, "Replace?", - [function() {doReplace(match);}, advance, - function() {replaceAll(cm, query, text)}]); - }; - var doReplace = function(match) { - cursor.replace(typeof query == "string" ? text : - text.replace(/\$(\d)/g, function(_, i) {return match[i];})); - advance(); - }; - advance(); - } - }); - }); + function replaceSelection(cm) { + var text = parseString(cm.state.search.text); + var query = parseQuery(cm.state.search.query); + var match = cm.getRange(cm.state.search.posFrom, cm.state.search.posTo).match(query); + cm.replaceSelection(typeof query == "string" ? text : + text.replace(/\$(\d)/g, function(_, i) {return match[i];})); } CodeMirror.commands.find = function(cm) {clearSearch(cm); doSearch(cm);}; @@ -247,6 +220,13 @@ CodeMirror.commands.findNext = doSearch; CodeMirror.commands.findPrev = function(cm) {doSearch(cm, true);}; CodeMirror.commands.clearSearch = clearSearch; - CodeMirror.commands.replace = replace; - CodeMirror.commands.replaceAll = function(cm) {replace(cm, true);}; + CodeMirror.commands.replace = replaceSelection; + CodeMirror.commands.replaceAll = function(cm) { + if (cm.getOption("readOnly")) return; + var query = cm.state.search.query; + var text = cm.state.search.text; + query = parseQuery(query); + text = parseString(text); + replaceAll(cm, query, text); + }; }); diff --git a/app/src/main/assets/editor/codemirror/lib/codemirror.css b/app/src/main/assets/editor/codemirror/lib/codemirror.css index 5836398c..1ded6ec4 100644 --- a/app/src/main/assets/editor/codemirror/lib/codemirror.css +++ b/app/src/main/assets/editor/codemirror/lib/codemirror.css @@ -6,7 +6,7 @@ height: 300px; color: black; direction: ltr; - font-size: 35px; + font-size: 13px; } /* PADDING */ diff --git a/app/src/main/assets/editor/index.html b/app/src/main/assets/editor/index.html index 8fdb5f72..4b851fdd 100644 --- a/app/src/main/assets/editor/index.html +++ b/app/src/main/assets/editor/index.html @@ -28,6 +28,7 @@ + @@ -36,6 +37,11 @@ + + + + + CodeMirrorEditor @@ -59,5 +65,6 @@ editor.on("keyup", function(cm, e) { editor.execCommand("autocomplete") }) + editor.setCursor({line: 0, ch: 0}); \ No newline at end of file diff --git a/app/src/main/java/com/stardust/scriptdroid/script/Scripts.java b/app/src/main/java/com/stardust/scriptdroid/script/Scripts.java index 8f25630c..9d723cba 100644 --- a/app/src/main/java/com/stardust/scriptdroid/script/Scripts.java +++ b/app/src/main/java/com/stardust/scriptdroid/script/Scripts.java @@ -3,7 +3,9 @@ package com.stardust.scriptdroid.script; import android.content.Context; import android.content.Intent; import android.net.Uri; +import android.support.annotation.Nullable; +import com.stardust.autojs.engine.RhinoJavaScriptEngine; import com.stardust.autojs.execution.ExecutionConfig; import com.stardust.autojs.execution.ScriptExecution; import com.stardust.autojs.execution.ScriptExecutionListener; @@ -21,6 +23,8 @@ import com.stardust.scriptdroid.script.sample.Sample; import com.stardust.scriptdroid.ui.edit.EditActivity; import com.stardust.util.AssetsCache; +import org.mozilla.javascript.RhinoException; + import java.io.File; /** @@ -31,6 +35,8 @@ public class Scripts { public static final String ACTION_ON_EXECUTION_FINISHED = "Don't leave me alone..."; public static final String EXTRA_EXCEPTION_MESSAGE = "Say something...Eating...17.5.3"; + public static final String EXTRA_EXCEPTION_LINE_NUMBER = "Can we fall in love with each other again...17.9.28"; + public static final String EXTRA_EXCEPTION_COLUMN_NUMBER = "I lost myself...."; private static final ScriptExecutionListener BROADCAST_SENDER_SCRIPT_EXECUTION_LISTENER = new SimpleScriptExecutionListener() { @@ -41,11 +47,21 @@ public class Scripts { @Override public void onException(ScriptExecution execution, Exception e) { + RhinoException rhinoException = getRhinoException(e); + int line = -1, col = 0; + if (rhinoException != null) { + line = rhinoException.lineNumber(); + col = rhinoException.columnNumber(); + } if (ScriptInterruptedException.causedByInterrupted(e)) { - App.getApp().sendBroadcast(new Intent(ACTION_ON_EXECUTION_FINISHED)); + App.getApp().sendBroadcast(new Intent(ACTION_ON_EXECUTION_FINISHED) + .putExtra(EXTRA_EXCEPTION_LINE_NUMBER, line) + .putExtra(EXTRA_EXCEPTION_COLUMN_NUMBER, col)); } else { App.getApp().sendBroadcast(new Intent(ACTION_ON_EXECUTION_FINISHED) - .putExtra(EXTRA_EXCEPTION_MESSAGE, e.getMessage())); + .putExtra(EXTRA_EXCEPTION_MESSAGE, e.getMessage()) + .putExtra(EXTRA_EXCEPTION_LINE_NUMBER, line) + .putExtra(EXTRA_EXCEPTION_COLUMN_NUMBER, col)); } } @@ -114,4 +130,15 @@ public class Scripts { .path(directoryPath, StorageFileProvider.DEFAULT_DIRECTORY_PATH) .loop(delay, loopTimes, interval)); } + + @Nullable + public static RhinoException getRhinoException(Throwable e) { + while (e != null) { + if (e instanceof RhinoException) { + return (RhinoException) e; + } + e = e.getCause(); + } + return null; + } } diff --git a/app/src/main/java/com/stardust/scriptdroid/ui/edit/CodeMirrorEditor.java b/app/src/main/java/com/stardust/scriptdroid/ui/edit/CodeMirrorEditor.java index c6f05b04..1545532a 100644 --- a/app/src/main/java/com/stardust/scriptdroid/ui/edit/CodeMirrorEditor.java +++ b/app/src/main/java/com/stardust/scriptdroid/ui/edit/CodeMirrorEditor.java @@ -15,6 +15,7 @@ import android.widget.FrameLayout; import com.stardust.pio.PFile; +import org.apache.commons.lang3.StringEscapeUtils; import org.jdeferred.Deferred; import org.jdeferred.DoneCallback; import org.jdeferred.impl.DeferredObject; @@ -40,6 +41,7 @@ public class CodeMirrorEditor extends FrameLayout { private static final String LOG_TAG = "CodeMirrorEditor"; + public interface Callback { void onChange(); @@ -54,6 +56,11 @@ public class CodeMirrorEditor extends FrameLayout { private Callback mCallback; private Deferred mPageFinished = new DeferredObject<>(); + private PublishSubject mStringFromJs; + private PublishSubject mIntFromJs; + private String mTextFromAndroid; + + public CodeMirrorEditor(Context context) { super(context); init(); @@ -143,9 +150,9 @@ public class CodeMirrorEditor extends FrameLayout { WebSettings settings = mWebView.getSettings(); settings.setUseWideViewPort(true); settings.setBuiltInZoomControls(true); - settings.setLoadWithOverviewMode(true); + //settings.setLoadWithOverviewMode(true); settings.setJavaScriptEnabled(true); - settings.setUseWideViewPort(true); + //settings.setUseWideViewPort(true); settings.setJavaScriptCanOpenWindowsAutomatically(true); settings.setDomStorageEnabled(true); settings.setNeedInitialFocus(true); @@ -159,15 +166,24 @@ public class CodeMirrorEditor extends FrameLayout { } public void setText(final String text) { - mJavaScriptBridge.mTextFromAndroid = text; + mTextFromAndroid = text; mPageFinished.promise().done(new DoneCallback() { @Override public void onDone(Void result) { - evalJavaScript("editor.setValue(__bridge__.getText());"); + evalJavaScript("editor.setValue(__bridge__.getStringFromAndroid());"); } }); } + public void insert(String text) { + mTextFromAndroid = text; + mPageFinished.promise().done(new DoneCallback() { + @Override + public void onDone(Void result) { + evalJavaScript("editor.replaceSelection(__bridge__.getStringFromAndroid());"); + } + }); + } public void loadFile(final File file) { setProgress(true); @@ -188,9 +204,26 @@ public class CodeMirrorEditor extends FrameLayout { } public Observable getText() { - mJavaScriptBridge.mTextFromJs = PublishSubject.create(); - evalJavaScript("__bridge__.setText(editor.getValue());"); - return mJavaScriptBridge.mTextFromJs; + mStringFromJs = PublishSubject.create(); + evalJavaScript("__bridge__.setStringFromJs(editor.getValue());"); + return mStringFromJs; + } + + public Observable getLine() { + mStringFromJs = PublishSubject.create(); + evalJavaScript("__bridge__.setStringFromJs(editor.getLine(editor.getCursor().line))"); + return mStringFromJs; + } + + public void deleteLine() { + evalJavaScript("editor.replaceRange('', {line: editor.getCursor().line, ch: 0}," + + " {line: editor.getCursor().line + 1, ch: 0});"); + } + + public Observable getLineCount() { + mIntFromJs = PublishSubject.create(); + evalJavaScript("__bridge__.setIntFromJs(editor.lineCount())"); + return mIntFromJs; } @@ -202,6 +235,50 @@ public class CodeMirrorEditor extends FrameLayout { evalJavaScript("editor.redo();"); } + public void jumpTo(int line, int col) { + evalJavaScript("editor.setCursor({line: " + line + ", ch: " + col + "});"); + } + + public void find(String keywords, boolean usingRegex) { + setQuery(keywords, usingRegex); + findNext(); + } + + private void setQuery(String keywords, boolean usingRegex) { + keywords = keywords.replace("'", "\'"); + if (usingRegex) { + keywords = "/" + keywords + "/"; + } + evalJavaScript("editor.execCommand('clearSearch'); editor.state.search.query = '" + + keywords + "';"); + } + + public void findNext() { + evalJavaScript("editor.execCommand('findNext');"); + } + + public void findPrev() { + evalJavaScript("editor.execCommand('findPrev');"); + } + + public void replaceAll(String keywords, String replacement, boolean usingRegex) { + setQuery(keywords, usingRegex); + replacement = replacement.replace("'", "\'"); + evalJavaScript("editor.state.search.text = '" + replacement + "';"); + evalJavaScript("editor.execCommand('replaceAll');"); + } + + public void replace(String keywords, String replacement, boolean usingRegex) { + setQuery(keywords, usingRegex); + replacement = replacement.replace("'", "\'"); + evalJavaScript("editor.state.search.text = '" + replacement + "';"); + findNext(); + } + + public void replaceSelection() { + evalJavaScript("editor.execCommand('replace');"); + } + private void evalJavaScript(String script) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) { mWebView.evaluateJavascript(script, null); @@ -217,27 +294,33 @@ public class CodeMirrorEditor extends FrameLayout { public class JavaScriptBridge { - private PublishSubject mTextFromJs; - private String mTextFromAndroid; - @JavascriptInterface - public void setText(String text) { - if (mTextFromJs != null) { - mTextFromJs.onNext(text); - mTextFromJs.onComplete(); - mTextFromJs = null; + public void setStringFromJs(String text) { + if (mStringFromJs != null) { + mStringFromJs.onNext(text); + mStringFromJs.onComplete(); + mStringFromJs = null; } } @JavascriptInterface - public String getText() { + public void setIntFromJs(int i) { + if (mIntFromJs != null) { + mIntFromJs.onNext(i); + mIntFromJs.onComplete(); + mIntFromJs = null; + } + } + + @JavascriptInterface + public String getStringFromAndroid() { String t = mTextFromAndroid; mTextFromAndroid = null; return t; } @JavascriptInterface - public void onChange() { + public void onTextChange() { if (mCallback != null) { mWebView.post(new Runnable() { @Override @@ -260,12 +343,11 @@ public class CodeMirrorEditor extends FrameLayout { } } - } private class MyWebViewClient extends WebViewClient { - private final String INIT_SCRIPT = "editor.on('change', function(){__bridge__.onChange();});"; + private final String INIT_SCRIPT = "editor.on('change', function(){__bridge__.onTextChange();});"; @Override public void onPageFinished(WebView view, String url) { diff --git a/app/src/main/java/com/stardust/scriptdroid/ui/edit/EditorMenu.java b/app/src/main/java/com/stardust/scriptdroid/ui/edit/EditorMenu.java index 7ecd8af7..c8c2377a 100644 --- a/app/src/main/java/com/stardust/scriptdroid/ui/edit/EditorMenu.java +++ b/app/src/main/java/com/stardust/scriptdroid/ui/edit/EditorMenu.java @@ -1,11 +1,24 @@ package com.stardust.scriptdroid.ui.edit; +import android.content.Context; +import android.support.design.widget.Snackbar; +import android.text.InputType; import android.view.MenuItem; -import com.stardust.autojs.engine.JavaScriptEngine; +import com.afollestad.materialdialogs.MaterialDialog; +import com.stardust.pio.PFile; import com.stardust.scriptdroid.R; import com.stardust.scriptdroid.autojs.AutoJs; -import com.stardust.scriptdroid.script.Scripts; +import com.stardust.theme.dialog.ThemeColorMaterialDialogBuilder; +import com.stardust.util.ClipboardUtil; + +import java.util.Locale; + +import io.reactivex.Observable; +import io.reactivex.android.schedulers.AndroidSchedulers; +import io.reactivex.annotations.NonNull; +import io.reactivex.functions.BiFunction; +import io.reactivex.functions.Consumer; /** * Created by Stardust on 2017/9/28. @@ -14,9 +27,13 @@ import com.stardust.scriptdroid.script.Scripts; public class EditorMenu { private EditorView mEditorView; + private Context mContext; + private CodeMirrorEditor mEditor; - public EditorMenu(EditorView editor) { - mEditorView = editor; + public EditorMenu(EditorView editorView) { + mEditorView = editorView; + mContext = editorView.getContext(); + mEditor = editorView.mEditor; } public boolean onOptionsItemSelected(MenuItem item) { @@ -27,22 +44,156 @@ public class EditorMenu { case R.id.action_log: showLog(); return true; - case R.id.action_editor_theme: - mEditorView.selectEditorTheme(); + case R.id.action_force_stop: + forceStop(); return true; + case R.id.action_jump: + jump(); + return true; + default: + if (onEditOptionsSelected(item)) { + return true; + } + if (onMoreOptionsSelected(item)) { + return true; + } + } + return false; + } + + + private boolean onMoreOptionsSelected(MenuItem item) { + switch (item.getItemId()) { case R.id.action_beautify: beautifyCode(); return true; + case R.id.action_editor_theme: + mEditorView.selectEditorTheme(); + return true; case R.id.action_open_by_other_apps: openByOtherApps(); return true; - case R.id.action_force_stop: - forceStop(); + case R.id.action_info: + showInfo(); + return true; + + } + return false; + } + + + private boolean onEditOptionsSelected(MenuItem item) { + switch (item.getItemId()) { + case R.id.action_find_or_replace: + findOrReplace(); + return true; + case R.id.action_copy_all: + copyAll(); + return true; + case R.id.action_paste: + paste(); + return true; + case R.id.action_copy_line: + copyLine(); + return true; + case R.id.action_delete_line: + deleteLine(); + return true; + case R.id.action_clear: + mEditor.setText(""); return true; } return false; } + private void jump() { + mEditor.getLineCount() + .observeOn(AndroidSchedulers.mainThread()) + .subscribe(new Consumer() { + @Override + public void accept(@NonNull Integer lineCount) throws Exception { + showJumpDialog(lineCount); + } + }); + } + + private void showJumpDialog(final int lineCount) { + String hint = "1 ~ " + lineCount; + new ThemeColorMaterialDialogBuilder(mContext) + .title(R.string.text_jump_to_line) + .input(hint, "", new MaterialDialog.InputCallback() { + @Override + public void onInput(@android.support.annotation.NonNull MaterialDialog dialog, CharSequence input) { + int line = Integer.parseInt(input.toString()); + mEditor.jumpTo(line - 1, 0); + } + }) + .inputType(InputType.TYPE_CLASS_NUMBER) + .show(); + } + + private void showInfo() { + Observable.zip(mEditor.getText(), mEditor.getLineCount(), new BiFunction() { + @Override + public String apply(@NonNull String text, @NonNull Integer lineCount) throws Exception { + String size = PFile.getHumanReadableSize(text.length()); + return String.format(Locale.getDefault(), mContext.getString(R.string.format_editor_info), + text.length(), lineCount, size); + } + }) + .observeOn(AndroidSchedulers.mainThread()) + .subscribe(new Consumer() { + @Override + public void accept(@NonNull String info) throws Exception { + showInfo(info); + } + }); + + } + + private void showInfo(String info) { + new ThemeColorMaterialDialogBuilder(mContext) + .title(R.string.text_info) + .content(info) + .show(); + } + + private void copyLine() { + mEditor.getLine() + .observeOn(AndroidSchedulers.mainThread()) + .subscribe(new Consumer() { + @Override + public void accept(@NonNull String s) throws Exception { + ClipboardUtil.setClip(mContext, s); + Snackbar.make(mEditorView, R.string.text_already_copy_to_clip, Snackbar.LENGTH_SHORT).show(); + } + }); + } + + + private void deleteLine() { + mEditor.deleteLine(); + } + + private void paste() { + mEditor.insert(ClipboardUtil.getClip(mContext).toString()); + } + + private void findOrReplace() { + new FindOrReplaceDialogBuilder(mContext, mEditorView) + .show(); + } + + private void copyAll() { + mEditor.getText().observeOn(AndroidSchedulers.mainThread()).subscribe(new Consumer() { + @Override + public void accept(@NonNull String s) throws Exception { + ClipboardUtil.setClip(mContext, s); + Snackbar.make(mEditorView, R.string.text_already_copy_to_clip, Snackbar.LENGTH_SHORT).show(); + } + }); + } + private void showLog() { AutoJs.getInstance().getScriptEngineService().getGlobalConsole().show(); @@ -52,7 +203,6 @@ public class EditorMenu { mEditorView.showConsole(); } - private void forceStop() { mEditorView.forceStop(); } diff --git a/app/src/main/java/com/stardust/scriptdroid/ui/edit/EditorView.java b/app/src/main/java/com/stardust/scriptdroid/ui/edit/EditorView.java index 6db9832d..e88052eb 100644 --- a/app/src/main/java/com/stardust/scriptdroid/ui/edit/EditorView.java +++ b/app/src/main/java/com/stardust/scriptdroid/ui/edit/EditorView.java @@ -20,6 +20,8 @@ import com.stardust.scriptdroid.R; import com.stardust.scriptdroid.script.Scripts; import com.stardust.scriptdroid.ui.edit.completion.CodeCompletions; import com.stardust.scriptdroid.ui.edit.completion.InputMethodEnhanceBar; +import com.stardust.widget.ToolbarMenuItem; +import com.stardust.widget.ViewSwitcher; import org.androidannotations.annotations.AfterViews; import org.androidannotations.annotations.Click; @@ -55,6 +57,12 @@ public class EditorView extends FrameLayout { @ViewById(R.id.input_method_enhance_bar) InputMethodEnhanceBar mInputMethodEnhanceBar; + @ViewById(R.id.toolbar_switcher) + ViewSwitcher mToolbarSwitcher; + + @ViewById(R.id.replace) + ToolbarMenuItem mReplaceMenuItem; + private static final String KEY_EDITOR_THEME = "我...深爱着...你呀...17.9.28"; private String mName; @@ -70,6 +78,11 @@ public class EditorView extends FrameLayout { mScriptExecution = null; setMenuItemStatus(R.id.run, true); String msg = intent.getStringExtra(Scripts.EXTRA_EXCEPTION_MESSAGE); + int line = intent.getIntExtra(Scripts.EXTRA_EXCEPTION_LINE_NUMBER, -1); + int col = intent.getIntExtra(Scripts.EXTRA_EXCEPTION_COLUMN_NUMBER, 0); + if (line >= 1) { + mEditor.jumpTo(line - 1, col); + } if (msg != null) { Snackbar.make(EditorView.this, getResources().getString(R.string.text_error) + ": " + msg, Snackbar.LENGTH_LONG).show(); } @@ -228,6 +241,26 @@ public class EditorView extends FrameLayout { save().subscribe(); } + @Click(R.id.find_next) + void findNext() { + mEditor.findNext(); + } + + @Click(R.id.find_prev) + void findPrev() { + mEditor.findPrev(); + } + + @Click(R.id.cancel) + void cancelSearch() { + mToolbarSwitcher.showFirst(); + } + + @Click(R.id.replace) + void replace() { + mEditor.replaceSelection(); + } + public String getName() { return mName; } @@ -273,4 +306,20 @@ public class EditorView extends FrameLayout { public CodeMirrorEditor getEditor() { return mEditor; } + + public void find(String keywords, boolean usingRegex) { + mEditor.find(keywords, usingRegex); + mReplaceMenuItem.setVisibility(GONE); + mToolbarSwitcher.showSecond(); + } + + public void replace(String keywords, String replacement, boolean usingRegex) { + mEditor.replace(keywords, replacement, usingRegex); + mReplaceMenuItem.setVisibility(VISIBLE); + mToolbarSwitcher.showSecond(); + } + + public void replaceAll(String keywords, String replacement, boolean usingRegex) { + mEditor.replaceAll(keywords, replacement, usingRegex); + } } diff --git a/app/src/main/java/com/stardust/scriptdroid/ui/edit/FindOrReplaceDialogBuilder.java b/app/src/main/java/com/stardust/scriptdroid/ui/edit/FindOrReplaceDialogBuilder.java new file mode 100644 index 00000000..602cc245 --- /dev/null +++ b/app/src/main/java/com/stardust/scriptdroid/ui/edit/FindOrReplaceDialogBuilder.java @@ -0,0 +1,123 @@ +package com.stardust.scriptdroid.ui.edit; + +import android.animation.ValueAnimator; +import android.content.Context; +import android.content.SharedPreferences; +import android.preference.PreferenceManager; +import android.support.annotation.NonNull; +import android.support.design.widget.TextInputEditText; +import android.text.TextUtils; +import android.view.View; +import android.view.ViewGroup; +import android.widget.CheckBox; +import android.widget.CompoundButton; +import android.widget.LinearLayout; + +import com.afollestad.materialdialogs.DialogAction; +import com.afollestad.materialdialogs.MaterialDialog; +import com.github.aakira.expandablelayout.ExpandableRelativeLayout; +import com.stardust.scriptdroid.R; +import com.stardust.theme.dialog.ThemeColorMaterialDialogBuilder; + +import butterknife.BindView; +import butterknife.ButterKnife; +import butterknife.OnCheckedChanged; +import butterknife.OnTextChanged; + +/** + * Created by Stardust on 2017/9/28. + */ + +public class FindOrReplaceDialogBuilder extends ThemeColorMaterialDialogBuilder { + + private static final String KEY_KEYWORDS = "你回来好不好..."; + + @BindView(R.id.checkbox_regex) + CheckBox mRegexCheckBox; + + @BindView(R.id.checkbox_replace) + CheckBox mReplaceCheckBox; + + @BindView(R.id.checkbox_replace_all) + CheckBox mReplaceAllCheckBox; + + @BindView(R.id.keywords) + TextInputEditText mKeywordsEditText; + + @BindView(R.id.replacement) + TextInputEditText mReplacementEditText; + + private EditorView mEditorView; + + + public FindOrReplaceDialogBuilder(@NonNull Context context, EditorView editorView) { + super(context); + mEditorView = editorView; + setupViews(); + restoreState(); + onPositive(new MaterialDialog.SingleButtonCallback() { + + @Override + public void onClick(@NonNull MaterialDialog dialog, @NonNull DialogAction which) { + storeState(); + findOrReplace(); + } + + }); + } + + private void setupViews() { + View view = View.inflate(context, R.layout.dialog_find_or_replace, null); + ButterKnife.bind(this, view); + customView(view, true); + positiveText(R.string.ok); + negativeText(R.string.cancel); + title(R.string.text_find_or_replace); + } + + + private void storeState() { + PreferenceManager.getDefaultSharedPreferences(getContext()).edit() + .putString(KEY_KEYWORDS, mKeywordsEditText.getText().toString()) + .apply(); + } + + + private void restoreState() { + mKeywordsEditText.setText(PreferenceManager.getDefaultSharedPreferences(getContext()) + .getString(KEY_KEYWORDS, "")); + } + + @OnCheckedChanged(R.id.checkbox_replace_all) + void syncWithReplaceCheckBox() { + if (mReplaceAllCheckBox.isChecked() && !mReplaceCheckBox.isChecked()) { + mReplaceCheckBox.setChecked(true); + } + } + + @OnTextChanged(R.id.replacement) + void onTextChanged() { + if (mReplacementEditText.getText().length() > 0) { + mReplaceCheckBox.setChecked(true); + } + } + + private void findOrReplace() { + String keywords = mKeywordsEditText.getText().toString(); + if (keywords.isEmpty()) { + return; + } + boolean usingRegex = mRegexCheckBox.isChecked(); + if (!mReplaceCheckBox.isChecked()) { + mEditorView.find(keywords, usingRegex); + } else { + String replacement = mReplacementEditText.getText().toString(); + if (mReplaceAllCheckBox.isChecked()) { + mEditorView.replaceAll(keywords, replacement, usingRegex); + } else { + mEditorView.replace(keywords, replacement, usingRegex); + } + } + + } +} diff --git a/app/src/main/res/drawable-hdpi/ic_close_white_48dp.png b/app/src/main/res/drawable-hdpi/ic_close_white_48dp.png new file mode 100644 index 00000000..6b717e0d Binary files /dev/null and b/app/src/main/res/drawable-hdpi/ic_close_white_48dp.png differ diff --git a/app/src/main/res/drawable-mdpi/ic_close_white_48dp.png b/app/src/main/res/drawable-mdpi/ic_close_white_48dp.png new file mode 100644 index 00000000..b7c7ffd0 Binary files /dev/null and b/app/src/main/res/drawable-mdpi/ic_close_white_48dp.png differ diff --git a/app/src/main/res/drawable-xhdpi/ic_close_white_48dp.png b/app/src/main/res/drawable-xhdpi/ic_close_white_48dp.png new file mode 100644 index 00000000..39641921 Binary files /dev/null and b/app/src/main/res/drawable-xhdpi/ic_close_white_48dp.png differ diff --git a/app/src/main/res/drawable-xxhdpi/ic_close_white_48dp.png b/app/src/main/res/drawable-xxhdpi/ic_close_white_48dp.png new file mode 100644 index 00000000..4927bc24 Binary files /dev/null and b/app/src/main/res/drawable-xxhdpi/ic_close_white_48dp.png differ diff --git a/app/src/main/res/drawable-xxxhdpi/ic_close_white_48dp.png b/app/src/main/res/drawable-xxxhdpi/ic_close_white_48dp.png new file mode 100644 index 00000000..1ab23127 Binary files /dev/null and b/app/src/main/res/drawable-xxxhdpi/ic_close_white_48dp.png differ diff --git a/app/src/main/res/drawable/ic_ali_down.png b/app/src/main/res/drawable/ic_ali_down.png new file mode 100644 index 00000000..d18c08a6 Binary files /dev/null and b/app/src/main/res/drawable/ic_ali_down.png differ diff --git a/app/src/main/res/drawable/ic_ali_replace.png b/app/src/main/res/drawable/ic_ali_replace.png new file mode 100644 index 00000000..8194fe84 Binary files /dev/null and b/app/src/main/res/drawable/ic_ali_replace.png differ diff --git a/app/src/main/res/drawable/ic_ali_up.png b/app/src/main/res/drawable/ic_ali_up.png new file mode 100644 index 00000000..4348d817 Binary files /dev/null and b/app/src/main/res/drawable/ic_ali_up.png differ diff --git a/app/src/main/res/drawable/ic_close.png b/app/src/main/res/drawable/ic_close.png deleted file mode 100644 index d960ded4..00000000 Binary files a/app/src/main/res/drawable/ic_close.png and /dev/null differ diff --git a/app/src/main/res/drawable/ic_close_green_48dp.png b/app/src/main/res/drawable/ic_close_green_48dp.png deleted file mode 100644 index 0a8ac8d0..00000000 Binary files a/app/src/main/res/drawable/ic_close_green_48dp.png and /dev/null differ diff --git a/app/src/main/res/layout/dialog_find_or_replace.xml b/app/src/main/res/layout/dialog_find_or_replace.xml new file mode 100644 index 00000000..a6b96714 --- /dev/null +++ b/app/src/main/res/layout/dialog_find_or_replace.xml @@ -0,0 +1,69 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + \ 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 90cc3284..e4c2c1fa 100644 --- a/app/src/main/res/layout/editor_view.xml +++ b/app/src/main/res/layout/editor_view.xml @@ -10,6 +10,7 @@ android:layout_height="wrap_content" android:theme="@style/AppTheme.AppBarOverlay"> + - + android:layout_gravity="right"> - + android:layout_gravity="right" + android:orientation="horizontal"> - + + + + + + + + + + + + android:layout_gravity="right" + android:orientation="horizontal"> - + - + + + - + + + + + + diff --git a/app/src/main/res/menu/menu_editor.xml b/app/src/main/res/menu/menu_editor.xml index dfc0365d..0b6fa50f 100644 --- a/app/src/main/res/menu/menu_editor.xml +++ b/app/src/main/res/menu/menu_editor.xml @@ -3,39 +3,86 @@ xmlns:app="http://schemas.android.com/apk/res-auto"> + + + + + + + + + + + + + + + + + + + + + + + - - - + + - + + + + + + + + \ 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 f22bafd2..3093cc4c 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -254,6 +254,22 @@ 类型 捐赠 编辑器主题 + 工具 + 跳转到行 + 信息 + 查找/替换 + 粘贴 + 复制全部 + 复制行 + 删除行 + 字符数: %d\n行数: %d\n大小: %s + 查找 + 替换 + 正则表达式 + 全部替换 + 向下 + 向上 + 正则语法与JavaScript中相同, 可使用$1-9代替被捕获的匹配 diff --git a/autojs/src/main/java/com/stardust/autojs/runtime/exception/ScriptException.java b/autojs/src/main/java/com/stardust/autojs/runtime/exception/ScriptException.java index 4925df9c..e9022c46 100644 --- a/autojs/src/main/java/com/stardust/autojs/runtime/exception/ScriptException.java +++ b/autojs/src/main/java/com/stardust/autojs/runtime/exception/ScriptException.java @@ -1,11 +1,13 @@ package com.stardust.autojs.runtime.exception; +import org.mozilla.javascript.EvaluatorException; +import org.mozilla.javascript.RhinoException; + /** * Created by Stardust on 2017/1/29. */ public class ScriptException extends RuntimeException { - public ScriptException(String message, Throwable cause) { super(message, cause); } @@ -15,7 +17,6 @@ public class ScriptException extends RuntimeException { } public ScriptException() { - } public ScriptException(Throwable cause) {