imporve code completion

This commit is contained in:
hyb1996
2017-07-21 17:05:01 +08:00
parent ab2ad906e7
commit 6d62b40b21
12 changed files with 476 additions and 136 deletions

View File

@@ -29,7 +29,7 @@
返回路径path是否是文件夹。
### files.isDirEmpty(path)
### files.isEmptyDir(path)
* path \<String\> 路径
返回文件夹path是否为空文件夹。如果该路径并非文件夹则直接返回false。

View File

@@ -1,62 +1,305 @@
[ "toast",
"app",
"launchPackage",
"launch",
"launchApp",
"getPackageName",
"openAppSetting",
"sleep",
"isStopped",
"notStopped",
"stop",
"console",
"log",
"print",
"err",
"openConsole",
"clearConsole",
"shell",
"currentPackage",
"currentActivity",
"back",
"home",
"powerDialog",
"notifications",
"quickSettings",
"recents",
"splitScreen",
"click",
"longClick",
"scrollDown",
"scrollUp",
"input",
"setClip",
"SetScreenMetrics",
"Tap",
"Swipe",
"Screencap",
"KeyCode",
"Home",
"Back",
"Power",
"Up",
"Down",
"Left",
"Right",
"OK",
"VolumeUp",
"VolumeDown",
"Menu",
"Camera",
"Text",
"selector",
"open",
"newInjectableWebClient",
"newInjectableWebView",
"dialogs",
"rawInput",
"input",
"alert",
"confirm",
"prompt"
]
{
"global" : {
"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"
]
},
"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",
"onKeyDown",
"onKeyUp",
"onceKeyDown",
"onceKeyUp",
"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"
]
}

View File

@@ -8,6 +8,8 @@ import com.stardust.autojs.runtime.api.AutomatorConfig;
import com.stardust.automator.AccessibilityEventCommandHost;
import com.stardust.scriptdroid.autojs.AutoJs;
import org.mozilla.javascript.NativeArray;
import java.util.concurrent.TimeUnit;
/**
@@ -143,8 +145,6 @@ public class Pref {
}
def().edit().putLong(KEY_LAST_SHOW_AD_MILLIS, System.currentTimeMillis()).apply();
return true;
case "Off":
return false;
}
return true;
}

View File

@@ -0,0 +1,32 @@
package com.stardust.scriptdroid.tool;
import com.google.gson.JsonArray;
import com.google.gson.JsonElement;
import java.util.ArrayList;
import java.util.List;
/**
* Created by Stardust on 2017/7/21.
*/
public class GsonUtils {
public static List<String> toReservedStringList(JsonElement element) {
JsonArray array = element.getAsJsonArray();
List<String> list = new ArrayList<>(array.size());
for (int i = array.size() - 1; i >= 0; i--) {
list.add(array.get(i).getAsString());
}
return list;
}
public static List<String> toStringList(JsonElement element) {
JsonArray array = element.getAsJsonArray();
List<String> list = new ArrayList<>(array.size());
for (int i = 0; i < array.size(); i++) {
list.add(array.get(i).getAsString());
}
return list;
}
}

View File

@@ -1,22 +1,20 @@
package com.stardust.scriptdroid.ui.edit.completion;
import android.content.Context;
import android.support.annotation.NonNull;
import android.text.Editable;
import android.text.TextUtils;
import android.text.TextWatcher;
import com.google.gson.Gson;
import com.stardust.pio.PFile;
import com.stardust.pio.UncheckedIOException;
import com.stardust.scriptdroid.App;
import com.stardust.scriptdroid.Pref;
import com.jecelyin.editor.v2.core.widget.TextView;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.TreeSet;
@@ -48,19 +46,26 @@ public class CodeCompletion implements TextWatcher {
}
@Override
public int compareTo(CodeCompletionItem o) {
public int compareTo(@NonNull CodeCompletionItem o) {
return mDisplayText.compareTo(o.mDisplayText);
}
}
interface OnCodeCompletionChangeListener {
void OnCodeCompletionChange(Collection<CodeCompletionItem>... list);
void OnCodeCompletionChange(@NonNull Collection<CodeCompletionItem> list1, @NonNull Collection<CodeCompletionItem> list2);
}
private static final String TAG = "CodeCompletion";
private OnCodeCompletionChangeListener mOnCodeCompletionChangeListener;
private TextView mEditText;
private static final List<String> KEYWORDS = Arrays.asList("arguments", "break", "case", "catch", "class", "continue", "default", "do", "else", "eval", "export", "false", "for", "function", "if", "import", "in", "int", "new", "null", "package", "return", "switch", "this", "throw", "throws", "true", "try", "typeof", "var", "volatile", "while", "with", "Array", "Date", "hasOwnProperty", "Infinity", "isFinite", "isNaN", "isPrototypeOf", "length", "Math", "NaN", "name", "Number", "Object", "prototype", "String", "toString", "undefined", "valueOf");
private static final int KEY_WORD_LENGTH_MAX = 15;
private List<String> mGlobal = Collections.emptyList();
private Map<String, List<String>> mVariableProperties = new HashMap<>();
public CodeCompletion(OnCodeCompletionChangeListener listener) {
mOnCodeCompletionChangeListener = listener;
@@ -71,6 +76,14 @@ public class CodeCompletion implements TextWatcher {
mEditText.addTextChangedListener(this);
}
public void setGlobal(List<String> functions) {
mGlobal = functions;
}
public void setVariableProperties(Map<String, List<String>> variableProperties) {
mVariableProperties = variableProperties;
}
@Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
}
@@ -82,60 +95,94 @@ public class CodeCompletion implements TextWatcher {
@Override
public void afterTextChanged(Editable s) {
int position = mEditText.getSelectionStart();
String str = parseWordBefore(s, position);
if (!TextUtils.isEmpty(str))
searchCodeCompletion(str);
else
mOnCodeCompletionChangeListener.OnCodeCompletionChange(DEFAULT_CODE_COMPLETION_LIST);
String[] str = parseWordBefore(s, position);
if (str != null) {
if (str[1] != null) {
searchCodeCompletionForVariable(str[0], str[1]);
} else {
searchCodeCompletionForGlobal(str[0]);
}
} else {
mOnCodeCompletionChangeListener.OnCodeCompletionChange(DEFAULT_CODE_COMPLETION_LIST, Collections.<CodeCompletionItem>emptyList());
}
}
private String parseWordBefore(Editable s, int position) {
private String[] parseWordBefore(Editable s, int position) {
int i;
for (i = position - 1; i >= 0; i--) {
if (position - i > KEY_WORD_LENGTH_MAX) {
return null;
}
char c = s.charAt(i);
if (c == '.') {
return new String[]{parseWordBeforeDot(s, i), s.subSequence(i + 1, position).toString()};
}
if (!Character.isLetter(s.charAt(i))) {
if (i < position - 1) {
return new String[]{s.subSequence(i + 1, position).toString(), null};
} else {
return null;
}
}
}
return null;
}
private String parseWordBeforeDot(Editable s, int position) {
int i;
for (i = position - 1; i >= 0; i--) {
if (position - i > KEY_WORD_LENGTH_MAX) {
return null;
}
if (!Character.isLetter(s.charAt(i))) {
break;
if (i < position - 1) {
return s.subSequence(i + 1, position).toString();
} else {
return null;
}
}
}
if (i < position - 1) {
return s.subSequence(i + 1, position).toString();
}
return null;
}
private static final String[] KEYWORDS = {"arguments", "break", "case", "catch", "class", "continue", "default", "do", "else", "eval", "export", "false", "for", "function", "if", "import", "in", "int", "new", "null", "package", "return", "switch", "this", "throw", "throws", "true", "try", "typeof", "var", "volatile", "while", "with", "Array", "Date", "hasOwnProperty", "Infinity", "isFinite", "isNaN", "isPrototypeOf", "length", "Math", "NaN", "name", "Number", "Object", "prototype", "String", "toString", "undefined", "valueOf"};
private static final int KEY_WORD_LENGTH_MAX = 15;
public void setFunctions(String[] functions) {
mFunctions = functions;
}
private String[] mFunctions = new String[0];
private boolean searchCodeCompletion(String str) {
private boolean searchCodeCompletionForGlobal(String str) {
Collection<CodeCompletionItem> c = searchWordCompletion(str);
c.addAll(searchCodeCompletion(str, mFunctions));
c.addAll(searchCodeCompletion(str, mGlobal));
c.addAll(searchKeyWordCompletion(str));
if (c.size() > 0) {
mOnCodeCompletionChangeListener.OnCodeCompletionChange(c, DEFAULT_CODE_COMPLETION_LIST);
return true;
} else {
mOnCodeCompletionChangeListener.OnCodeCompletionChange(DEFAULT_CODE_COMPLETION_LIST);
mOnCodeCompletionChangeListener.OnCodeCompletionChange(DEFAULT_CODE_COMPLETION_LIST, Collections.<CodeCompletionItem>emptyList());
return false;
}
}
private boolean searchCodeCompletionForVariable(String variable, String str) {
List<String> properties = getPropertiesForVariable(variable);
Collection<CodeCompletionItem> c = searchCodeCompletion(str, properties);
mOnCodeCompletionChangeListener.OnCodeCompletionChange(c, Collections.<CodeCompletionItem>emptyList());
return !c.isEmpty();
}
private List<String> getPropertiesForVariable(String str) {
List<String> properties = mVariableProperties.get(str);
if (properties == null)
return Collections.emptyList();
return properties;
}
private Collection<CodeCompletionItem> searchWordCompletion(String str) {
if (mEditText.getEditableText().length() < Pref.getMaxTextLengthForCodeCompletion()) {
return searchCodeCompletion(str, splitWord(mEditText.getEditableText().toString()));
return searchCodeCompletion(str, Arrays.asList(splitWord(mEditText.getEditableText().toString())));
}
return new TreeSet<>();
}
private Collection<CodeCompletionItem> searchCodeCompletion(String str, String[] words) {
private Collection<CodeCompletionItem> searchCodeCompletion(String str, Iterable<String> words) {
Set<CodeCompletionItem> set = new TreeSet<>();
for (String word : words) {
// TODO: 2017/2/18 优化 字典树

View File

@@ -3,8 +3,8 @@ package com.stardust.scriptdroid.ui.edit.completion;
import android.content.ClipData;
import android.content.ClipboardManager;
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.util.AttributeSet;
import android.view.LayoutInflater;
@@ -15,21 +15,27 @@ import android.widget.Toast;
import android.workground.WrapContentLinearLayoutManager;
import com.google.gson.Gson;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.google.gson.JsonParser;
import com.stardust.pio.UncheckedIOException;
import com.stardust.scriptdroid.App;
import com.stardust.scriptdroid.R;
import com.stardust.scriptdroid.autojs.AutoJs;
import com.stardust.scriptdroid.tool.GsonUtils;
import com.stardust.util.UnderuseExecutors;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* Created by Stardust on 2017/2/17.
*/
// TODO: 2017/7/21 refactor
public class InputMethodEnhanceBar extends RecyclerView implements CodeCompletion.OnCodeCompletionChangeListener {
@@ -48,6 +54,14 @@ public class InputMethodEnhanceBar extends RecyclerView implements CodeCompletio
init();
}
@Override
public void OnCodeCompletionChange(@NonNull Collection<CodeCompletion.CodeCompletionItem> list1, @NonNull Collection<CodeCompletion.CodeCompletionItem> list2) {
mCodeCompletionList.clear();
mCodeCompletionList.addAll(list1);
mCodeCompletionList.addAll(list2);
getAdapter().notifyDataSetChanged();
}
public interface EditTextBridge {
void appendText(CharSequence text);
@@ -56,6 +70,9 @@ public class InputMethodEnhanceBar extends RecyclerView implements CodeCompletio
com.jecelyin.editor.v2.core.widget.TextView getEditText();
}
private static List<String> global;
private static Map<String, List<String>> variables = new HashMap<>();
EditTextBridge mEditTextBridge;
private CodeCompletion mCodeCompletion = new CodeCompletion(this);
private List<CodeCompletion.CodeCompletionItem> mCodeCompletionList = new ArrayList<>();
@@ -83,7 +100,16 @@ public class InputMethodEnhanceBar extends RecyclerView implements CodeCompletio
private void init() {
setAdapter(new CodeCompletionAdapter());
setLayoutManager(new WrapContentLinearLayoutManager(getContext(), HORIZONTAL, false));
mCodeCompletion.setFunctions(readFunctions(getContext(), "js/functions.json"));
if (global == null) {
UnderuseExecutors.execute(new Runnable() {
@Override
public void run() {
readCompletions(getContext(), "js/functions.json");
mCodeCompletion.setGlobal(global);
mCodeCompletion.setVariableProperties(variables);
}
});
}
}
public void setEditTextBridge(EditTextBridge editTextBridge) {
@@ -91,16 +117,6 @@ public class InputMethodEnhanceBar extends RecyclerView implements CodeCompletio
mCodeCompletion.setEditText(mEditTextBridge.getEditText());
}
@Override
public void OnCodeCompletionChange(Collection<CodeCompletion.CodeCompletionItem>... lists) {
mCodeCompletionList.clear();
for (Collection<CodeCompletion.CodeCompletionItem> list : lists) {
mCodeCompletionList.addAll(list);
}
getAdapter().notifyDataSetChanged();
}
private class CodeCompletionAdapter extends RecyclerView.Adapter<ViewHolder> {
@@ -129,13 +145,29 @@ public class InputMethodEnhanceBar extends RecyclerView implements CodeCompletio
}
}
private static String[] readFunctions(Context context, String path) {
Gson gson = new Gson();
private static void readCompletions(Context context, String path) {
try {
return gson.fromJson(new InputStreamReader(context.getAssets().open(path)), String[].class);
JsonParser parser = new JsonParser();
JsonObject object = parser.parse(new InputStreamReader(context.getAssets().open(path))).getAsJsonObject();
InputMethodEnhanceBar.global = readGlobal(object.remove("global").getAsJsonObject());
readModules(object);
} catch (IOException e) {
throw new UncheckedIOException(e);
}
}
private static void readModules(JsonObject object) {
for (Map.Entry<String, JsonElement> module : object.entrySet()) {
variables.put(module.getKey(), GsonUtils.toStringList(module.getValue()));
}
}
private static List<String> readGlobal(JsonObject global) {
List<String> globalFunctions = new ArrayList<>();
for (Map.Entry<String, JsonElement> moduleGlobal : global.entrySet()) {
globalFunctions.addAll(GsonUtils.toStringList(moduleGlobal.getValue()));
}
return globalFunctions;
}
}

View File

@@ -228,13 +228,11 @@
<string-array name="ad_showing_mode_keys">
<item>默认</item>
<item>每天显示一次</item>
<item>关闭广告</item>
</string-array>
<string-array name="ad_showing_mode_values">
<item>Default</item>
<item>OncePerDay</item>
<item>Off</item>
</string-array>
</resources>