From c1141485028c5b21f371c0aea68b6fc2d8c56ae0 Mon Sep 17 00:00:00 2001 From: hyb1996 <946994919@qq.com> Date: Fri, 29 Sep 2017 13:47:19 +0800 Subject: [PATCH] add: refactor, jumping for editor --- .../addon/autojs/autojs-global-scope.js | 338 +++++++++++++++ .../editor/codemirror/addon/autojs/autojs.js | 395 +++--------------- app/src/main/assets/editor/index.html | 39 +- app/src/main/assets/editor/index.js | 24 ++ .../scriptdroid/ui/edit/CodeMirrorEditor.java | 110 ++++- .../scriptdroid/ui/edit/EditorMenu.java | 71 +++- .../ui/edit/FindOrReplaceDialogBuilder.java | 6 + app/src/main/res/menu/menu_editor.xml | 71 +++- app/src/main/res/values/strings.xml | 11 +- 9 files changed, 684 insertions(+), 381 deletions(-) create mode 100644 app/src/main/assets/editor/codemirror/addon/autojs/autojs-global-scope.js create mode 100644 app/src/main/assets/editor/index.js diff --git a/app/src/main/assets/editor/codemirror/addon/autojs/autojs-global-scope.js b/app/src/main/assets/editor/codemirror/addon/autojs/autojs-global-scope.js new file mode 100644 index 00000000..0e9606e1 --- /dev/null +++ b/app/src/main/assets/editor/codemirror/addon/autojs/autojs-global-scope.js @@ -0,0 +1,338 @@ +function autoJsGlobalScope(){ + var globals = { + "modules": [ + "app", + "automator", + "console", + "dialogs", + "events", + "images", + "files", + "timers", + "ui", + ], + "app": [ + "launchPackage", + "launch", + "launchApp", + "getPackageName", + "openAppSetting" + ], + "automator": [ + "click", + "longClick", + "press", + "swipe", + "gesture", + "gestures", + "gestureAsync", + "gesturesAsync", + "scrollDown", + "scrollUp", + "input", + "setText" + ], + "console": [ + "print", + "log", + "err", + "openConsole", + "clearConsole" + ], + "dialogs": [ + "rawInput", + "input", + "alert", + "confirm", + "prompt" + ], + "images": [ + "requestScreenCapture", + "captureScreen", + "findColor", + "findColorInRegion", + "findColorEquals" + ], + "files": [ + "open" + ], + "selector": [ + "id", + "idContains", + "idStartsWith", + "idEndsWith", + "idMatches", + "text", + "textContains", + "textStartsWith", + "textEndsWith", + "textMatches", + "desc", + "descContains", + "descStartsWith", + "descEndsWith", + "descMatches", + "className", + "classNameContains", + "classNameStartsWith", + "classNameEndsWith", + "classNameMatches", + "packageName", + "packageNameContains", + "packageNameStartsWith", + "packageNameEndsWith", + "packageNameMatches", + "bounds", + "boundsInside", + "boundsContains", + "drawingOrder", + "checkable", + "checked", + "focusable", + "focused", + "visibleToUser", + "accessibilityFocused", + "selected", + "clickable", + "longClickable", + "enabled", + "password", + "scrollable", + "editable", + "contentInvalid", + "contextClickable", + "multiLine", + "dismissable", + "checkable", + "checked", + "focusable", + "focused", + "visibleToUser", + "accessibilityFocused", + "selected", + "clickable", + "longClickable", + "enabled", + "password", + "scrollable", + "editable", + "contentInvalid", + "contextClickable", + "multiLine", + "dismissable" + ], + "shell": [ + "SetScreenMetrics", + "Tap", + "Swipe", + "Screencap", + "KeyCode", + "Home", + "Back", + "Power", + "Up", + "Down", + "Left", + "Right", + "OK", + "VolumeUp", + "VolumeDown", + "Menu", + "Camera", + "Text" + ], + "timers": [ + "loop", + "setTimeout", + "clearTimeout", + "setInterval", + "clearInterval", + "setImmediate", + "clearImmediate" + ], + "web": [ + "newInjectableWebClient", + "newInjectableWebView" + ], + "general": [ + "toast", + "toastLog", + "sleep", + "isStopped", + "notStopped", + "exit", + "setClip", + "getClip", + "currentPackage", + "currentActivity", + "waitForActivity", + "waitForPackage", + "setScreenMetrics" + ], + "variables": [ + "context", + "activity" + ] + }; + var modules = { + "app": [ + "uninstall", + "viewFile", + "editFile", + "openUrl", + "launchPackage", + "launch", + "launchApp", + "getPackageName", + "openAppSetting" + ], + "automator": [ + "click", + "longClick", + "press", + "swipe", + "gesture", + "gestures", + "gestureAsync", + "gesturesAsync", + "scrollDown", + "scrollUp", + "input", + "setText" + ], + "console": [ + "show", + "hide", + "clear", + "verbose", + "print", + "info", + "log", + "warn", + "error", + "assert" + ], + "dialogs": [ + "select", + "singleChoice", + "multiChoice", + "rawInput", + "input", + "alert", + "confirm", + "prompt" + ], + "images": [ + "saveImage", + "pixel", + "read", + "requestScreenCapture", + "captureScreen", + "findColor", + "findColorInRegion", + "findColorEquals" + ], + "colors": [ + "red", + "green", + "blue", + "alpha", + "toString", + "rgb", + "argb" + ], + "events": [ + "emitter", + "observeKey", + "observeTouch", + "observeNotification", + "onKeyDown", + "onKeyUp", + "onceKeyDown", + "onceKeyUp", + "onToast", + "onNotification", + "removeAllKeyDownListeners", + "removeAllKeyUpListeners", + "onTouch", + "removeAllTouchListeners", + "getTouchEventTimeout", + "setTouchEventTimeout", + "on", + "once", + "emit", + "getListeners", + "addListener", + "eventNames", + "listenerCount", + "listeners", + "prependListener", + "prependOnceListener", + "removeAllListeners", + "removeAllListeners", + "removeListener", + "setMaxListeners", + "getMaxListeners", + "defaultMaxListeners" + ], + "files": [ + "open", + "isFile", + "isDir", + "isEmptyDir", + "join", + "create", + "createIfNotExists", + "exists", + "ensureDir", + "read", + "write", + "copy", + "rename", + "renameWithoutExtension", + "getName", + "getExtension", + "remove", + "removeDir", + "getSdcardPath", + "listDir" + ], + "timers": [ + "loop", + "setTimeout", + "clearTimeout", + "setInterval", + "clearInterval", + "setImmediate", + "clearImmediate" + ] + }; + function for_each(obj, func){ + for(var key in obj){ + if(!obj.hasOwnProperty(key)){ + continue; + } + func(key, obj[key]); + } + } + var __global__ = {}; + for_each(modules, function(moduleName, moduleVariables){ + if(!__global__[moduleName]){ + __global__[moduleName] = {}; + } + for(var i = 0; i < moduleVariables.length; i++){ + if(!__global__[moduleName][moduleVariables[i]]){ + __global__[moduleName][moduleVariables[i]] = ''; + } + } + }); + for_each(globals, function(moduleName, moduleVariables){ + for(var i = 0; i < moduleVariables.length; i++){ + if(!__global__[moduleVariables[i]]){ + __global__[moduleVariables[i]] = ''; + } + } + }) + return __global__; + } + diff --git a/app/src/main/assets/editor/codemirror/addon/autojs/autojs.js b/app/src/main/assets/editor/codemirror/addon/autojs/autojs.js index 0e9606e1..30b175f6 100644 --- a/app/src/main/assets/editor/codemirror/addon/autojs/autojs.js +++ b/app/src/main/assets/editor/codemirror/addon/autojs/autojs.js @@ -1,338 +1,61 @@ -function autoJsGlobalScope(){ - var globals = { - "modules": [ - "app", - "automator", - "console", - "dialogs", - "events", - "images", - "files", - "timers", - "ui", - ], - "app": [ - "launchPackage", - "launch", - "launchApp", - "getPackageName", - "openAppSetting" - ], - "automator": [ - "click", - "longClick", - "press", - "swipe", - "gesture", - "gestures", - "gestureAsync", - "gesturesAsync", - "scrollDown", - "scrollUp", - "input", - "setText" - ], - "console": [ - "print", - "log", - "err", - "openConsole", - "clearConsole" - ], - "dialogs": [ - "rawInput", - "input", - "alert", - "confirm", - "prompt" - ], - "images": [ - "requestScreenCapture", - "captureScreen", - "findColor", - "findColorInRegion", - "findColorEquals" - ], - "files": [ - "open" - ], - "selector": [ - "id", - "idContains", - "idStartsWith", - "idEndsWith", - "idMatches", - "text", - "textContains", - "textStartsWith", - "textEndsWith", - "textMatches", - "desc", - "descContains", - "descStartsWith", - "descEndsWith", - "descMatches", - "className", - "classNameContains", - "classNameStartsWith", - "classNameEndsWith", - "classNameMatches", - "packageName", - "packageNameContains", - "packageNameStartsWith", - "packageNameEndsWith", - "packageNameMatches", - "bounds", - "boundsInside", - "boundsContains", - "drawingOrder", - "checkable", - "checked", - "focusable", - "focused", - "visibleToUser", - "accessibilityFocused", - "selected", - "clickable", - "longClickable", - "enabled", - "password", - "scrollable", - "editable", - "contentInvalid", - "contextClickable", - "multiLine", - "dismissable", - "checkable", - "checked", - "focusable", - "focused", - "visibleToUser", - "accessibilityFocused", - "selected", - "clickable", - "longClickable", - "enabled", - "password", - "scrollable", - "editable", - "contentInvalid", - "contextClickable", - "multiLine", - "dismissable" - ], - "shell": [ - "SetScreenMetrics", - "Tap", - "Swipe", - "Screencap", - "KeyCode", - "Home", - "Back", - "Power", - "Up", - "Down", - "Left", - "Right", - "OK", - "VolumeUp", - "VolumeDown", - "Menu", - "Camera", - "Text" - ], - "timers": [ - "loop", - "setTimeout", - "clearTimeout", - "setInterval", - "clearInterval", - "setImmediate", - "clearImmediate" - ], - "web": [ - "newInjectableWebClient", - "newInjectableWebView" - ], - "general": [ - "toast", - "toastLog", - "sleep", - "isStopped", - "notStopped", - "exit", - "setClip", - "getClip", - "currentPackage", - "currentActivity", - "waitForActivity", - "waitForPackage", - "setScreenMetrics" - ], - "variables": [ - "context", - "activity" - ] - }; - var modules = { - "app": [ - "uninstall", - "viewFile", - "editFile", - "openUrl", - "launchPackage", - "launch", - "launchApp", - "getPackageName", - "openAppSetting" - ], - "automator": [ - "click", - "longClick", - "press", - "swipe", - "gesture", - "gestures", - "gestureAsync", - "gesturesAsync", - "scrollDown", - "scrollUp", - "input", - "setText" - ], - "console": [ - "show", - "hide", - "clear", - "verbose", - "print", - "info", - "log", - "warn", - "error", - "assert" - ], - "dialogs": [ - "select", - "singleChoice", - "multiChoice", - "rawInput", - "input", - "alert", - "confirm", - "prompt" - ], - "images": [ - "saveImage", - "pixel", - "read", - "requestScreenCapture", - "captureScreen", - "findColor", - "findColorInRegion", - "findColorEquals" - ], - "colors": [ - "red", - "green", - "blue", - "alpha", - "toString", - "rgb", - "argb" - ], - "events": [ - "emitter", - "observeKey", - "observeTouch", - "observeNotification", - "onKeyDown", - "onKeyUp", - "onceKeyDown", - "onceKeyUp", - "onToast", - "onNotification", - "removeAllKeyDownListeners", - "removeAllKeyUpListeners", - "onTouch", - "removeAllTouchListeners", - "getTouchEventTimeout", - "setTouchEventTimeout", - "on", - "once", - "emit", - "getListeners", - "addListener", - "eventNames", - "listenerCount", - "listeners", - "prependListener", - "prependOnceListener", - "removeAllListeners", - "removeAllListeners", - "removeListener", - "setMaxListeners", - "getMaxListeners", - "defaultMaxListeners" - ], - "files": [ - "open", - "isFile", - "isDir", - "isEmptyDir", - "join", - "create", - "createIfNotExists", - "exists", - "ensureDir", - "read", - "write", - "copy", - "rename", - "renameWithoutExtension", - "getName", - "getExtension", - "remove", - "removeDir", - "getSdcardPath", - "listDir" - ], - "timers": [ - "loop", - "setTimeout", - "clearTimeout", - "setInterval", - "clearInterval", - "setImmediate", - "clearImmediate" - ] - }; - function for_each(obj, func){ - for(var key in obj){ - if(!obj.hasOwnProperty(key)){ - continue; - } - func(key, obj[key]); +function autojs(editor){ + function loadJs(url){ + var script = document.createElement("script"); + // This script has a callback function that will run when the script has + // finished loading. + script.src = url; + script.type = "text/javascript"; + document.getElementsByTagName("head")[0].appendChild(script); + } + var server = null; + var getURL = function(url, c) { + var xhr = new XMLHttpRequest(); + xhr.open("get", url, true); + xhr.send(); + xhr.onreadystatechange = function() { + if (xhr.readyState != 4) return; + if (xhr.status < 400) return c(null, xhr.responseText); + var e = new Error(xhr.responseText || "No response"); + e.status = xhr.status; + c(e); + }; + } + connect(); + editor.tern = {}; + editor.tern.showType = function(){ + checkServer(); + server.showType(editor); + } + editor.tern.jumpToDef = function(){ + checkServer(); + server.jumpToDef(editor); + } + editor.tern.rename = function(){ + checkServer(); + server.rename(editor); + } + editor.tern.selectName = function(){ + checkServer(); + server.selectName(editor); + } + editor.tern.jumpBack = function(){ + checkServer(); + server.jumpBack(editor); + } + + function connect(){ + getURL("http://ternjs.net/defs/ecmascript.json", function(err, code) { + if (err) throw new Error("Request for ecmascript.json: " + err); + server = new CodeMirror.TernServer({defs: [JSON.parse(code)]}); + editor.tern.server = server; + editor.on("cursorActivity", function(cm) { server.updateArgHints(cm); }); + }); + } + + function checkServer(){ + if(!server){ + alert("Error: cannot connect to tern server\n联网获取编辑器增强服务失败:(\n"); + connect(); } } - var __global__ = {}; - for_each(modules, function(moduleName, moduleVariables){ - if(!__global__[moduleName]){ - __global__[moduleName] = {}; - } - for(var i = 0; i < moduleVariables.length; i++){ - if(!__global__[moduleName][moduleVariables[i]]){ - __global__[moduleName][moduleVariables[i]] = ''; - } - } - }); - for_each(globals, function(moduleName, moduleVariables){ - for(var i = 0; i < moduleVariables.length; i++){ - if(!__global__[moduleVariables[i]]){ - __global__[moduleVariables[i]] = ''; - } - } - }) - return __global__; - } - +} \ No newline at end of file diff --git a/app/src/main/assets/editor/index.html b/app/src/main/assets/editor/index.html index a609b7f2..5a7e440f 100644 --- a/app/src/main/assets/editor/index.html +++ b/app/src/main/assets/editor/index.html @@ -42,6 +42,7 @@ +
@@ -50,26 +51,20 @@ - + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/assets/editor/index.js b/app/src/main/assets/editor/index.js new file mode 100644 index 00000000..ac50530a --- /dev/null +++ b/app/src/main/assets/editor/index.js @@ -0,0 +1,24 @@ +var editor = CodeMirror.fromTextArea(document.getElementById("code"), { + lineNumbers: true, // 显示行数 + indentUnit: 4, // 缩进单位为4 + styleActiveLine: true, // 当前行背景高亮 + foldGutter: true, + gutters:["CodeMirror-linenumbers", "CodeMirror-foldgutter"], + matchBrackets: true, // 括号匹配 + mode: 'javascript', + lineWrapping: false, // 自动换行 + theme: 'neo' // 使用neo主题 +}); +editor.setOption("fullScreen", true); +editor.setOption("hintOptions", { + completeSingle: false, + globalScope: autoJsGlobalScope() +}); +editor.on("keyup", function(cm, e) { + editor.execCommand("autocomplete"); +}) +editor.setCursor({line: 0, ch: 0}); + +window.onload = function(){ + autojs(editor); +} 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 1545532a..4c132fba 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 @@ -1,19 +1,26 @@ package com.stardust.scriptdroid.ui.edit; import android.content.Context; +import android.content.DialogInterface; import android.os.Build; import android.support.annotation.RequiresApi; import android.util.AttributeSet; import android.util.TypedValue; import android.view.Gravity; import android.webkit.JavascriptInterface; +import android.webkit.JsPromptResult; +import android.webkit.JsResult; import android.webkit.WebChromeClient; import android.webkit.WebSettings; import android.webkit.WebView; import android.webkit.WebViewClient; import android.widget.FrameLayout; +import com.afollestad.materialdialogs.DialogAction; +import com.afollestad.materialdialogs.MaterialDialog; import com.stardust.pio.PFile; +import com.stardust.scriptdroid.R; +import com.stardust.theme.dialog.ThemeColorMaterialDialogBuilder; import org.apache.commons.lang3.StringEscapeUtils; import org.jdeferred.Deferred; @@ -24,6 +31,8 @@ import java.io.File; import java.io.IOException; import java.util.Locale; import java.util.concurrent.Callable; +import java.util.regex.Matcher; +import java.util.regex.Pattern; import io.reactivex.Observable; import io.reactivex.android.schedulers.AndroidSchedulers; @@ -32,6 +41,7 @@ import io.reactivex.functions.Consumer; import io.reactivex.schedulers.Schedulers; import io.reactivex.subjects.PublishSubject; import me.zhanghai.android.materialprogressbar.MaterialProgressBar; +import retrofit2.http.GET; /** * Created by Stardust on 2017/9/27. @@ -41,7 +51,6 @@ public class CodeMirrorEditor extends FrameLayout { private static final String LOG_TAG = "CodeMirrorEditor"; - public interface Callback { void onChange(); @@ -158,7 +167,7 @@ public class CodeMirrorEditor extends FrameLayout { settings.setNeedInitialFocus(true); settings.setDisplayZoomControls(false); mWebView.setWebViewClient(new MyWebViewClient()); - mWebView.setWebChromeClient(new WebChromeClient()); + mWebView.setWebChromeClient(new MyWebChromeClient()); } public void setProgress(boolean onProgress) { @@ -268,6 +277,41 @@ public class CodeMirrorEditor extends FrameLayout { evalJavaScript("editor.execCommand('replaceAll');"); } + public void jumpToDef() { + evalJavaScript("editor.tern.jumpToDef();"); + } + + + public void jumpToLineStart() { + evalJavaScript("editor.execCommand('goLineStart');"); + } + + public void jumpToLineEnd() { + evalJavaScript("editor.execCommand('goLineEnd')"); + } + + public void jumpToStart() { + evalJavaScript("editor.execCommand('goDocStart');"); + } + + public void jumpToEnd() { + evalJavaScript("editor.execCommand('goDocEnd');"); + } + + + public void showType() { + evalJavaScript("editor.tern.showType();"); + } + + public void rename() { + evalJavaScript("editor.tern.rename();"); + } + + public void selectName() { + evalJavaScript("editor.tern.selectName();"); + } + + public void replace(String keywords, String replacement, boolean usingRegex) { setQuery(keywords, usingRegex); replacement = replacement.replace("'", "\'"); @@ -275,6 +319,12 @@ public class CodeMirrorEditor extends FrameLayout { findNext(); } + public Observable