package com.stardust.scriptdroid.ui.edit.completion; import android.content.Context; 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.Collection; import java.util.List; import java.util.Set; import java.util.TreeSet; /** * Created by Stardust on 2017/2/17. */ public class CodeCompletion implements TextWatcher { public static class CodeCompletionItem implements Comparable<CodeCompletionItem> { String mDisplayText, mAppendText; CodeCompletionItem(String displayText, String appendText) { mDisplayText = displayText; mAppendText = appendText; } CodeCompletionItem(String text) { this(text, text); } public String getAppendText() { return mAppendText; } public String getDisplayText() { return mDisplayText; } @Override public int compareTo(CodeCompletionItem o) { return mDisplayText.compareTo(o.mDisplayText); } } interface OnCodeCompletionChangeListener { void OnCodeCompletionChange(Collection<CodeCompletionItem>... list); } private static final String TAG = "CodeCompletion"; private OnCodeCompletionChangeListener mOnCodeCompletionChangeListener; private TextView mEditText; public CodeCompletion(OnCodeCompletionChangeListener listener) { mOnCodeCompletionChangeListener = listener; } public void setEditText(TextView editText) { mEditText = editText; mEditText.addTextChangedListener(this); } @Override public void beforeTextChanged(CharSequence s, int start, int count, int after) { } @Override public void onTextChanged(CharSequence s, int start, int before, int count) { } @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); } 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; } if (!Character.isLetter(s.charAt(i))) { break; } } 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) { Collection<CodeCompletionItem> c = searchWordCompletion(str); c.addAll(searchCodeCompletion(str, mFunctions)); c.addAll(searchKeyWordCompletion(str)); if (c.size() > 0) { mOnCodeCompletionChangeListener.OnCodeCompletionChange(c, DEFAULT_CODE_COMPLETION_LIST); return true; } else { mOnCodeCompletionChangeListener.OnCodeCompletionChange(DEFAULT_CODE_COMPLETION_LIST); return false; } } private Collection<CodeCompletionItem> searchWordCompletion(String str) { if (mEditText.getEditableText().length() < Pref.getMaxTextLengthForCodeCompletion()) { return searchCodeCompletion(str, splitWord(mEditText.getEditableText().toString())); } return new TreeSet<>(); } private Collection<CodeCompletionItem> searchCodeCompletion(String str, String[] words) { Set<CodeCompletionItem> set = new TreeSet<>(); for (String word : words) { // TODO: 2017/2/18 优化 字典树 if (word.startsWith(str) && str.length() < word.length()) { set.add(new CodeCompletionItem(word, word.substring(str.length()))); } } return set; } private String[] splitWord(String s) { // TODO: 2017/2/18 优化。利用上次结果 return s.split("[\\W]"); } private Collection<CodeCompletionItem> searchKeyWordCompletion(String str) { return searchCodeCompletion(str, KEYWORDS); } private static final String[] DEFAULT_CODE_COMPLETIONS = new String[]{"=", "(", ")", ";", "{", "}", "\"", "!", "[", "]", "\\", ">", "<", ".", ", "}; private static final List<CodeCompletionItem> DEFAULT_CODE_COMPLETION_LIST = new ArrayList<>(); static { for (String str : DEFAULT_CODE_COMPLETIONS) { DEFAULT_CODE_COMPLETION_LIST.add(new CodeCompletionItem(str)); } } }