imporve code completion
This commit is contained in:
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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 优化 字典树
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user