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

@@ -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;
}
}