mirror of
https://gitee.com/zhangsken/AndroidIDE.git
synced 2026-10-16 07:49:44 +08:00
v1.0.3-alpha
- Implemented 'Go to Definition' - Partially implemented 'Find all references' (without UI)
This commit is contained in:
@@ -6,9 +6,7 @@ import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.IntentFilter;
|
||||
import android.graphics.Color;
|
||||
import android.graphics.PorterDuff;
|
||||
import android.graphics.Rect;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.graphics.drawable.GradientDrawable;
|
||||
import android.os.Bundle;
|
||||
import android.text.SpannableStringBuilder;
|
||||
@@ -33,6 +31,7 @@ import com.blankj.utilcode.util.FileUtils;
|
||||
import com.blankj.utilcode.util.IntentUtils;
|
||||
import com.blankj.utilcode.util.KeyboardUtils;
|
||||
import com.blankj.utilcode.util.SizeUtils;
|
||||
import com.blankj.utilcode.util.ThrowableUtils;
|
||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder;
|
||||
import com.google.android.material.navigation.NavigationView;
|
||||
import com.google.android.material.tabs.TabLayout;
|
||||
@@ -43,6 +42,7 @@ import com.google.gson.JsonElement;
|
||||
import com.google.gson.JsonParser;
|
||||
import com.itsaky.androidide.adapters.DiagnosticsAdapter;
|
||||
import com.itsaky.androidide.adapters.EditorPagerAdapter;
|
||||
import com.itsaky.androidide.adapters.SearchListAdapter;
|
||||
import com.itsaky.androidide.adapters.viewholders.FileTreeViewHolder;
|
||||
import com.itsaky.androidide.app.StudioActivity;
|
||||
import com.itsaky.androidide.databinding.ActivityEditorBinding;
|
||||
@@ -67,12 +67,14 @@ import com.itsaky.androidide.syntax.colorschemes.SchemeAndroidIDE;
|
||||
import com.itsaky.androidide.tasks.GradleTask;
|
||||
import com.itsaky.androidide.tasks.TaskExecutor;
|
||||
import com.itsaky.androidide.utils.Environment;
|
||||
import com.itsaky.androidide.utils.Logger;
|
||||
import com.itsaky.androidide.utils.PreferenceManager;
|
||||
import com.itsaky.androidide.utils.ProjectWriter;
|
||||
import com.itsaky.androidide.utils.Symbols;
|
||||
import com.itsaky.androidide.utils.TypefaceUtils;
|
||||
import com.itsaky.androidide.utils.VersionedFileManager;
|
||||
import com.itsaky.androidide.views.MaterialBanner;
|
||||
import com.itsaky.androidide.views.SymbolInputView;
|
||||
import com.itsaky.lsp.Diagnostic;
|
||||
import com.itsaky.lsp.DidChangeTextDocumentParams;
|
||||
import com.itsaky.lsp.DidChangeWatchedFilesParams;
|
||||
@@ -85,9 +87,12 @@ import com.itsaky.lsp.JavaColors;
|
||||
import com.itsaky.lsp.JavaReportProgressParams;
|
||||
import com.itsaky.lsp.JavaStartProgressParams;
|
||||
import com.itsaky.lsp.LanguageClient;
|
||||
import com.itsaky.lsp.Location;
|
||||
import com.itsaky.lsp.Message;
|
||||
import com.itsaky.lsp.ParameterInformation;
|
||||
import com.itsaky.lsp.PublishDiagnosticsParams;
|
||||
import com.itsaky.lsp.Range;
|
||||
import com.itsaky.lsp.ReferenceParams;
|
||||
import com.itsaky.lsp.ShowMessageParams;
|
||||
import com.itsaky.lsp.SignatureHelp;
|
||||
import com.itsaky.lsp.SignatureInformation;
|
||||
@@ -108,7 +113,6 @@ import java.util.Stack;
|
||||
import java.util.regex.Pattern;
|
||||
import me.piruin.quickaction.ActionItem;
|
||||
import me.piruin.quickaction.QuickAction;
|
||||
import com.itsaky.androidide.views.SymbolInputView;
|
||||
|
||||
public class EditorActivity extends StudioActivity implements FileTreeFragment.FileActionListener,
|
||||
IDEService.BuildListener,
|
||||
@@ -129,6 +133,7 @@ public class EditorActivity extends StudioActivity implements FileTreeFragment.F
|
||||
private CodeEditor buildView;
|
||||
private CodeEditor logView;
|
||||
private RecyclerView diagnosticList;
|
||||
private RecyclerView searchResultList;
|
||||
private SymbolInputView symbolInput;
|
||||
|
||||
private LogLanguageImpl mLogLanguageImpl;
|
||||
@@ -262,6 +267,10 @@ public class EditorActivity extends StudioActivity implements FileTreeFragment.F
|
||||
if(getDiagnosticsList().getParent() != null && getDiagnosticsList().getParent() instanceof ViewGroup) {
|
||||
((ViewGroup) getDiagnosticsList().getParent()).removeView(getDiagnosticsList());
|
||||
}
|
||||
|
||||
if(getSearchResultList().getParent() != null && getSearchResultList().getParent() instanceof ViewGroup) {
|
||||
((ViewGroup) getSearchResultList().getParent()).removeView(getSearchResultList());
|
||||
}
|
||||
|
||||
mBinding.buildOutcontainer.addView(getBuildView(), new ViewGroup.LayoutParams(-1, -1));
|
||||
mBinding.buildContainer.setVisibility(View.GONE);
|
||||
@@ -277,6 +286,11 @@ public class EditorActivity extends StudioActivity implements FileTreeFragment.F
|
||||
mBinding.diagContainer.setVisibility(View.GONE);
|
||||
mBinding.diagToolbar.setNavigationOnClickListener(v -> hideDiagnostics());
|
||||
mBinding.diagToolbar.setOnClickListener(v -> hideDiagnostics());
|
||||
|
||||
mBinding.searchResultsListContainer.addView(getSearchResultList(), new ViewGroup.LayoutParams(-1, -1));
|
||||
mBinding.searchResultsContainer.setVisibility(View.GONE);
|
||||
mBinding.searchResultsToolbar.setNavigationOnClickListener(v -> hideSearchResults());
|
||||
mBinding.searchResultsToolbar.setOnClickListener(v -> hideSearchResults());
|
||||
|
||||
mBinding.viewOptionsCard.setVisibility(View.GONE);
|
||||
mBinding.transformScrim.setVisibility(View.GONE);
|
||||
@@ -284,6 +298,7 @@ public class EditorActivity extends StudioActivity implements FileTreeFragment.F
|
||||
mBinding.transformScrim.setOnClickListener(v -> hideViewOptions());
|
||||
mBinding.viewBuildOut.setOnClickListener(v -> showBuildResult());
|
||||
mBinding.viewDiags.setOnClickListener(v -> showDiagnostics());
|
||||
mBinding.viewSearchResults.setOnClickListener(v -> showSearchResults());
|
||||
mBinding.viewLogs.setOnClickListener(v -> showLogResult());
|
||||
mBinding.viewFiles.setOnClickListener(v -> showFiles());
|
||||
mBinding.viewDaemonStatus.setOnClickListener(v -> showDaemonStatus());
|
||||
@@ -334,6 +349,8 @@ public class EditorActivity extends StudioActivity implements FileTreeFragment.F
|
||||
hideViewOptions();
|
||||
} else if(mBinding.diagContainer.getVisibility() == View.VISIBLE) {
|
||||
hideDiagnostics();
|
||||
} else if(mBinding.searchResultsContainer.getVisibility() == View.VISIBLE) {
|
||||
hideSearchResults();
|
||||
} else if(mFileOptionsFragment != null && mFileOptionsFragment.isShowing()) {
|
||||
mFileOptionsFragment.dismiss();
|
||||
} else {
|
||||
@@ -661,6 +678,20 @@ public class EditorActivity extends StudioActivity implements FileTreeFragment.F
|
||||
mBinding.diagContainer.setVisibility(View.GONE);
|
||||
mBinding.viewOptionsCard.setVisibility(View.VISIBLE);
|
||||
}
|
||||
|
||||
private void showSearchResults() {
|
||||
TransitionManager.beginDelayedTransition(mBinding.getRoot(), createContainerTransformFor(mBinding.viewSearchResults, mBinding.searchResultsContainer));
|
||||
mBinding.diagContainer.setVisibility(View.VISIBLE);
|
||||
mBinding.viewOptionsCard.setVisibility(View.GONE);
|
||||
hideToolbarAndTabs();
|
||||
}
|
||||
|
||||
private void hideSearchResults() {
|
||||
showToolbarAndTabs();
|
||||
TransitionManager.beginDelayedTransition(mBinding.getRoot(), createContainerTransformFor(mBinding.searchResultsContainer, mBinding.viewSearchResults));
|
||||
mBinding.diagContainer.setVisibility(View.GONE);
|
||||
mBinding.viewOptionsCard.setVisibility(View.VISIBLE);
|
||||
}
|
||||
|
||||
private MaterialContainerTransform createContainerTransformFor(View start, View end) {
|
||||
return createContainerTransformFor(start, end, mBinding.realContainer);
|
||||
@@ -917,6 +948,72 @@ public class EditorActivity extends StudioActivity implements FileTreeFragment.F
|
||||
server.signatureHelp(params, file);
|
||||
else addPendingMessage(createMessage(JavaLanguageServer.Method.DID_SAVE, gson.toJson(params)));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void findDefinition(TextDocumentPositionParams params) {
|
||||
final JavaLanguageServer server = getApp().getJavaLanguageServer();
|
||||
if(server == null) return;
|
||||
server.findDefinition(params);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void gotoDefinition(List<Location> locations) {
|
||||
if(locations == null || locations.size() <= 0) {
|
||||
getApp().toast(R.string.msg_no_definition, Toaster.Type.ERROR);
|
||||
return;
|
||||
}
|
||||
Location loc = locations.get(0);
|
||||
final File file = new File(loc.uri);
|
||||
final Range range = loc.range;
|
||||
try {
|
||||
if(mPagerAdapter == null) return;
|
||||
if(mPagerAdapter.getCount() <= 0) {
|
||||
openFile(file, range);
|
||||
return;
|
||||
}
|
||||
EditorFragment frag = mPagerAdapter.getFrag(mBinding.tabs.getSelectedTabPosition());
|
||||
if(frag != null
|
||||
&& frag.getFile() != null
|
||||
&& frag.getEditor() != null
|
||||
&& frag.getFile().getAbsolutePath().equals(file.getAbsolutePath())) {
|
||||
if(range.start.equals(range.end)) {
|
||||
frag.getEditor().setSelection(range.start.line, range.start.character);
|
||||
} else {
|
||||
frag.getEditor().setSelectionRegion(range.start.line, range.start.character, range.end.line, range.end.character);
|
||||
}
|
||||
} else {
|
||||
openFile(file, range);
|
||||
EditorFragment opened = mPagerAdapter.findEditorByFile(file);
|
||||
if(opened != null && opened.getEditor() != null) {
|
||||
CodeEditor editor = opened.getEditor();
|
||||
editor.post(() -> {
|
||||
if(range.start.equals(range.end)) {
|
||||
editor.setSelection(range.start.line, range.start.character);
|
||||
} else {
|
||||
editor.setSelectionRegion(range.start.line, range.start.character, range.end.line, range.end.character);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
} catch (Throwable th) {
|
||||
Logger.instance().e(ThrowableUtils.getFullStackTrace(th));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void findReferences(ReferenceParams params) {
|
||||
final JavaLanguageServer server = getApp().getJavaLanguageServer();
|
||||
if(server == null) return;
|
||||
server.findReferences(params);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void references(List<Location> references) {
|
||||
if(references == null || references.size() <= 0) {
|
||||
getApp().toast(R.string.msg_no_references, Toaster.Type.INFO);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
private void addPendingMessage(Message msg) {
|
||||
pendingMessages.push(msg);
|
||||
@@ -1105,6 +1202,17 @@ public class EditorActivity extends StudioActivity implements FileTreeFragment.F
|
||||
return diagnosticList;
|
||||
}
|
||||
|
||||
private RecyclerView getSearchResultList() {
|
||||
return searchResultList == null ? createSearchResultList() : searchResultList;
|
||||
}
|
||||
|
||||
private RecyclerView createSearchResultList() {
|
||||
searchResultList = new RecyclerView(this);
|
||||
searchResultList.setLayoutManager(new LinearLayoutManager(this));
|
||||
searchResultList.setAdapter(new SearchListAdapter());
|
||||
return searchResultList;
|
||||
}
|
||||
|
||||
private List<DiagnosticGroup> mapAsGroup(Map<File, List<Diagnostic>> diags) {
|
||||
List<DiagnosticGroup> groups = new ArrayList<>();
|
||||
if(diags == null || diags.size() <= 0)
|
||||
@@ -1129,12 +1237,22 @@ public class EditorActivity extends StudioActivity implements FileTreeFragment.F
|
||||
|
||||
@Override
|
||||
public void openFile(File file) {
|
||||
int i = mPagerAdapter.openFile(file, this, this);
|
||||
if(i >= 0 && !mBinding.tabs.getTabAt(i).isSelected())
|
||||
mBinding.tabs.getTabAt(i).select();
|
||||
mBinding.editorDrawerLayout.closeDrawer(GravityCompat.END);
|
||||
invalidateOptionsMenu();
|
||||
openFile(file, null);
|
||||
}
|
||||
|
||||
public EditorFragment openFile(File file, Range selection) {
|
||||
if(selection == null) selection = Range.ofZero();
|
||||
int i = mPagerAdapter.openFile(file, selection, this, this);
|
||||
if(i >= 0 && !mBinding.tabs.getTabAt(i).isSelected())
|
||||
mBinding.tabs.getTabAt(i).select();
|
||||
mBinding.editorDrawerLayout.closeDrawer(GravityCompat.END);
|
||||
invalidateOptionsMenu();
|
||||
try {
|
||||
return mPagerAdapter.getFrag(i);
|
||||
} catch (Throwable th) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onOpenSuccessful(File file, String text) {
|
||||
|
||||
@@ -10,6 +10,7 @@ import java.io.File;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import com.itsaky.androidide.interfaces.JLSRequestor;
|
||||
import com.itsaky.lsp.Range;
|
||||
|
||||
public class EditorPagerAdapter extends FragmentStatePagerAdapter
|
||||
{
|
||||
@@ -36,21 +37,28 @@ public class EditorPagerAdapter extends FragmentStatePagerAdapter
|
||||
mFragments.addAll(fragments);
|
||||
}
|
||||
|
||||
public EditorFragment findEditorByFile(File file) {
|
||||
public int findIndexOfEditorByFile(File file) {
|
||||
for(int i=0;i<mFragments.size();i++) {
|
||||
Fragment frag = mFragments.get(i);
|
||||
if(!(frag instanceof EditorFragment))
|
||||
continue;
|
||||
|
||||
|
||||
EditorFragment editor = (EditorFragment) frag;
|
||||
if(editor.getFile() != null && editor.getFile().getAbsolutePath().equals(file.getAbsolutePath()))
|
||||
return editor;
|
||||
return i;
|
||||
}
|
||||
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
public EditorFragment findEditorByFile(File file) {
|
||||
int index = findIndexOfEditorByFile(file);
|
||||
if(index != -1)
|
||||
return getFrag(index);
|
||||
return null;
|
||||
}
|
||||
|
||||
public int openFile(File file, EditorFragment.FileOpenListener listener, JLSRequestor jlsRequestor)
|
||||
public int openFile(File file, Range selection, EditorFragment.FileOpenListener listener, JLSRequestor jlsRequestor)
|
||||
{
|
||||
int openedFileIndex = -1;
|
||||
for(int i=0;i<mOpenedFiles.size();i++)
|
||||
@@ -66,7 +74,7 @@ public class EditorPagerAdapter extends FragmentStatePagerAdapter
|
||||
if(openedFileIndex == -1)
|
||||
{
|
||||
mFragments.add(EditorFragment
|
||||
.newInstance(file, project)
|
||||
.newInstance(file, project, selection)
|
||||
.setFileOpenListener(listener)
|
||||
.setJLSRequestor(jlsRequestor));
|
||||
mOpenedFiles.add(file);
|
||||
|
||||
@@ -0,0 +1,7 @@
|
||||
package com.itsaky.androidide.adapters;
|
||||
|
||||
public class SearchListAdapter {
|
||||
|
||||
|
||||
|
||||
}
|
||||
@@ -57,6 +57,11 @@ public class EditorFragment extends BaseFragment implements EditorEventListener
|
||||
|
||||
public static final String KEY_FILE_PATH = "file_path";
|
||||
public static final String KEY_PROJECT = "project";
|
||||
public static final String KEY_LINE_START = "line_start";
|
||||
public static final String KEY_LINE_END = "line_end";
|
||||
public static final String KEY_COLUMN_START = "col_start";
|
||||
public static final String KEY_COLUMN_END = "col_end";
|
||||
|
||||
public static final String EXT_JAVA = ".java";
|
||||
public static final String EXT_XML = ".xml";
|
||||
public static final String EXT_HTML = ".html";
|
||||
@@ -78,9 +83,13 @@ public class EditorFragment extends BaseFragment implements EditorEventListener
|
||||
}
|
||||
}
|
||||
|
||||
public static EditorFragment newInstance(File file, AndroidProject project) {
|
||||
public static EditorFragment newInstance(File file, AndroidProject project, Range selection) {
|
||||
Bundle bundle = new Bundle();
|
||||
bundle.putString(KEY_FILE_PATH, file.getAbsolutePath());
|
||||
bundle.putInt(KEY_LINE_START, selection.start.line);
|
||||
bundle.putInt(KEY_LINE_END, selection.end.line);
|
||||
bundle.putInt(KEY_COLUMN_START, selection.start.character);
|
||||
bundle.putInt(KEY_COLUMN_END, selection.end.character);
|
||||
bundle.putParcelable(KEY_PROJECT, project);
|
||||
EditorFragment frag = new EditorFragment();
|
||||
frag.setArguments(bundle);
|
||||
@@ -134,11 +143,36 @@ public class EditorFragment extends BaseFragment implements EditorEventListener
|
||||
|
||||
configureEditorIfNeeded();
|
||||
|
||||
final Range range = fromArgs(getArguments());
|
||||
new TaskExecutor().executeAsync(new ReadFileTask(mFile), result -> {
|
||||
binding.editor.setText(result);
|
||||
postRead();
|
||||
binding.editor.post(() -> {
|
||||
if(range.start.equals(range.end)) {
|
||||
getEditor().setSelection(range.start.line, range.start.character);
|
||||
} else {
|
||||
getEditor().setSelectionRegion(range.start.line, range.start.character, range.end.line, range.end.character);
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
private Range fromArgs(Bundle args) {
|
||||
if(!(args.containsKey(KEY_LINE_START)
|
||||
&& args.containsKey(KEY_COLUMN_START)
|
||||
&& args.containsKey(KEY_LINE_END)
|
||||
&& args.containsKey(KEY_COLUMN_END)))
|
||||
return Range.ofZero();
|
||||
|
||||
return new Range(
|
||||
new Position(
|
||||
args.getInt(KEY_LINE_START),
|
||||
args.getInt(KEY_COLUMN_START)),
|
||||
new Position(
|
||||
args.getInt(KEY_LINE_END),
|
||||
args.getInt(KEY_COLUMN_END)
|
||||
));
|
||||
}
|
||||
|
||||
public void setDiagnostics(List<Diagnostic> diags) {
|
||||
if(binding.editor != null && diags != null) {
|
||||
|
||||
@@ -7,6 +7,7 @@ import com.itsaky.lsp.DidOpenTextDocumentParams;
|
||||
import com.itsaky.lsp.DidSaveTextDocumentParams;
|
||||
import com.itsaky.lsp.TextDocumentPositionParams;
|
||||
import java.io.File;
|
||||
import com.itsaky.lsp.ReferenceParams;
|
||||
|
||||
public interface JLSRequestor {
|
||||
|
||||
@@ -19,4 +20,6 @@ public interface JLSRequestor {
|
||||
void didChangeWatchedFiles(DidChangeWatchedFilesParams params);
|
||||
|
||||
void signatureHelp(TextDocumentPositionParams params, File file);
|
||||
void findDefinition(TextDocumentPositionParams params);
|
||||
void findReferences(ReferenceParams params);
|
||||
}
|
||||
|
||||
+64
-2
@@ -12,6 +12,7 @@ import com.itsaky.androidide.app.StudioApp;
|
||||
import com.itsaky.androidide.models.AndroidProject;
|
||||
import com.itsaky.androidide.shell.ShellServer;
|
||||
import com.itsaky.androidide.utils.Environment;
|
||||
import com.itsaky.androidide.utils.FileUtil;
|
||||
import com.itsaky.androidide.utils.Logger;
|
||||
import com.itsaky.lsp.CancelParams;
|
||||
import com.itsaky.lsp.CodeActionParams;
|
||||
@@ -37,6 +38,7 @@ import com.itsaky.lsp.TextEdit;
|
||||
import java.io.BufferedOutputStream;
|
||||
import java.io.BufferedReader;
|
||||
import java.io.File;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStreamReader;
|
||||
import java.io.OutputStream;
|
||||
@@ -46,6 +48,9 @@ import java.util.List;
|
||||
import java.util.concurrent.ArrayBlockingQueue;
|
||||
import java.util.concurrent.BlockingQueue;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import com.itsaky.lsp.Location;
|
||||
import com.google.gson.reflect.TypeToken;
|
||||
import com.itsaky.lsp.ReferenceParams;
|
||||
|
||||
public class JavaLanguageServer implements ShellServer.Callback {
|
||||
|
||||
@@ -60,6 +65,8 @@ public class JavaLanguageServer implements ShellServer.Callback {
|
||||
|
||||
private final ConcurrentHashMap<Integer, Integer> completionRequests = new ConcurrentHashMap<>();
|
||||
private final ConcurrentHashMap<Integer, Integer> formattingRequests = new ConcurrentHashMap<>();
|
||||
private final ConcurrentHashMap<Integer, Integer> definitionRequests = new ConcurrentHashMap<>();
|
||||
private final ConcurrentHashMap<Integer, Integer> referencesRequests = new ConcurrentHashMap<>();
|
||||
private final ConcurrentHashMap<Integer, File> signatureRequests = new ConcurrentHashMap<>();
|
||||
|
||||
private final BlockingQueue<CompletionList> completionResponseQueue = new ArrayBlockingQueue<>(20);
|
||||
@@ -226,6 +233,16 @@ public class JavaLanguageServer implements ShellServer.Callback {
|
||||
signatureRequests.put(id, file);
|
||||
}
|
||||
|
||||
public void findDefinition(TextDocumentPositionParams params) {
|
||||
int id = write(Method.DEFINITION, gson.toJson(params));
|
||||
definitionRequests.put(id, id);
|
||||
}
|
||||
|
||||
public void findReferences(ReferenceParams params) {
|
||||
int id = write(Method.REFERENCES, gson.toJson(params));
|
||||
referencesRequests.put(id, id);
|
||||
}
|
||||
|
||||
public void cancelRequest(int requestId) {
|
||||
CancelParams p = new CancelParams();
|
||||
p.id = requestId;
|
||||
@@ -266,12 +283,41 @@ public class JavaLanguageServer implements ShellServer.Callback {
|
||||
|
||||
@Override
|
||||
public void output(CharSequence charSequence) {
|
||||
writeOut(charSequence.toString());
|
||||
}
|
||||
|
||||
private BufferedOutputStream os;
|
||||
private BufferedOutputStream os1;
|
||||
|
||||
private void writeOut(String data) {
|
||||
try {
|
||||
if(os == null) {
|
||||
os = new BufferedOutputStream(new FileOutputStream(new File(FileUtil.getExternalStorageDir(), "ide_xlog/out.txt"), true));
|
||||
}
|
||||
os.write(data.getBytes());
|
||||
os.flush();
|
||||
} catch (Throwable th) {
|
||||
logger.e(ThrowableUtils.getFullStackTrace(th));
|
||||
}
|
||||
}
|
||||
|
||||
private void writeOut2(String data) {
|
||||
try {
|
||||
if(os1 == null) {
|
||||
os1 = new BufferedOutputStream(new FileOutputStream(new File(FileUtil.getExternalStorageDir(), "ide_xlog/verbose.txt"), true));
|
||||
}
|
||||
os1.write(data.getBytes());
|
||||
os1.flush();
|
||||
} catch (Throwable th) {
|
||||
logger.e(ThrowableUtils.getFullStackTrace(th));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This method is called on UI Thread, do not perform time consuming or networking tasks
|
||||
*/
|
||||
private void onServerOut(String line) {
|
||||
writeOut2(line + "\n");
|
||||
if(line.contains(CONTENT_LENGTH)) line = line.substring(0, line.lastIndexOf(CONTENT_LENGTH));
|
||||
if(this.client == null) return;
|
||||
try {
|
||||
@@ -294,11 +340,10 @@ public class JavaLanguageServer implements ShellServer.Callback {
|
||||
client.javaProgressEnd();
|
||||
} else if(method.equals(Method.JAVA_COLORS)) {
|
||||
JavaColors colors = gson.fromJson(obj.get(Key.PARAMS).toString(), JavaColors.class);
|
||||
logger.v(colors.toString());
|
||||
client.javaColors(colors);
|
||||
}
|
||||
} else if(obj.has(Key.ID)) {
|
||||
int id = obj.get(Key.ID).getAsInt();
|
||||
final int id = obj.get(Key.ID).getAsInt();
|
||||
if(completionRequests.containsKey(id)) {
|
||||
final CompletionList list = gson.fromJson(obj.get(Key.RESULT).getAsJsonObject(), CompletionList.class);
|
||||
completionResponseQueue.put(list);
|
||||
@@ -311,6 +356,22 @@ public class JavaLanguageServer implements ShellServer.Callback {
|
||||
} catch ( Throwable th) {
|
||||
client.signatureHelp(null, null);
|
||||
}
|
||||
} else if(definitionRequests.containsKey(id)) {
|
||||
try {
|
||||
final List<Location> locations = gson.fromJson(obj.get(Key.RESULT).getAsJsonArray(), new TypeToken<List<Location>>(){}.getType());
|
||||
if(locations != null && locations.size() > 0)
|
||||
client.gotoDefinition(locations);
|
||||
} catch (Throwable th) {
|
||||
client.gotoDefinition(null);
|
||||
}
|
||||
} else if(referencesRequests.containsKey(id)) {
|
||||
try {
|
||||
final List<Location> locations = gson.fromJson(obj.get(Key.RESULT).getAsJsonArray(), new TypeToken<List<Location>>(){}.getType());
|
||||
if(locations != null && locations.size() > 0)
|
||||
client.references(locations);
|
||||
} catch (Throwable th) {
|
||||
client.references(null);
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (Throwable th) {
|
||||
@@ -339,6 +400,7 @@ public class JavaLanguageServer implements ShellServer.Callback {
|
||||
public static final String HOVER = "textDocument/hover";
|
||||
public static final String SIGNATURE_HELP = "textDocument/signatureHelp";
|
||||
public static final String DEFINITION = "textDocument/definition";
|
||||
public static final String REFERENCES = "textDocument/references";
|
||||
|
||||
public static final String PREPARE_RENAME = "textDocument/prepareRename";
|
||||
public static final String RENAME = "textDocument/rename";
|
||||
|
||||
@@ -96,6 +96,12 @@ import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import com.itsaky.androidide.utils.Logger;
|
||||
import com.blankj.utilcode.util.ThrowableUtils;
|
||||
import com.itsaky.lsp.TextDocumentPositionParams;
|
||||
import com.itsaky.lsp.TextDocumentIdentifier;
|
||||
import com.itsaky.lsp.ReferenceParams;
|
||||
import com.itsaky.lsp.ReferenceContext;
|
||||
|
||||
/**
|
||||
* CodeEditor is a editor that can highlight text regions by doing basic syntax analyzing
|
||||
@@ -4414,6 +4420,31 @@ public class CodeEditor extends View implements ContentListener, TextAnalyzer.Ca
|
||||
public void uncommentSelected() {
|
||||
|
||||
}
|
||||
|
||||
public void findDefinition() {
|
||||
if(jlsRequestor == null || getFile() == null) return;
|
||||
try {
|
||||
TextDocumentPositionParams params = new TextDocumentPositionParams();
|
||||
params.position = new Position(getCursor().getLeftLine(), getCursor().getLeftColumn());
|
||||
params.textDocument = new TextDocumentIdentifier(getFile().toURI());
|
||||
jlsRequestor.findDefinition(params);
|
||||
} catch (Throwable th) {
|
||||
Logger.instance("CodeEditor").e(ThrowableUtils.getFullStackTrace(th));
|
||||
}
|
||||
}
|
||||
|
||||
public void findReferences() {
|
||||
if(jlsRequestor == null || getFile() == null) return;
|
||||
try {
|
||||
ReferenceParams params = new ReferenceParams();
|
||||
params.context = new ReferenceContext(true);
|
||||
params.position = new Position(getCursor().getLeftLine(), getCursor().getLeftColumn());
|
||||
params.textDocument = new TextDocumentIdentifier(getFile().toURI());
|
||||
jlsRequestor.findReferences(params);
|
||||
} catch (Throwable th) {
|
||||
Logger.instance("CodeEditor").e(ThrowableUtils.getFullStackTrace(th));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void afterInsert(Content content, int startLine, int startColumn, int endLine, int endColumn, CharSequence insertedContent) {
|
||||
|
||||
@@ -68,7 +68,8 @@ class EditorTextActionModeStarter implements CodeEditor.EditorTextActionPresente
|
||||
menu.add(0, 3, 0, mEditor.getContext().getString(android.R.string.paste))
|
||||
.setShowAsActionFlags(2)
|
||||
.setIcon(array.getDrawable(3));
|
||||
|
||||
menu.add(0, 4, 0, "Go to Definition");
|
||||
menu.add(0, 5, 0, "Find all references");
|
||||
array.recycle();
|
||||
return true;
|
||||
}
|
||||
@@ -86,16 +87,22 @@ class EditorTextActionModeStarter implements CodeEditor.EditorTextActionPresente
|
||||
break;
|
||||
case 1:
|
||||
mEditor.cutText();
|
||||
onExit();
|
||||
break;
|
||||
case 2:
|
||||
mEditor.copyText();
|
||||
onExit();
|
||||
break;
|
||||
case 3:
|
||||
mEditor.pasteText();
|
||||
onExit();
|
||||
break;
|
||||
case 4:
|
||||
mEditor.findDefinition();
|
||||
break;
|
||||
case 5:
|
||||
mEditor.findReferences();
|
||||
break;
|
||||
}
|
||||
if(menuItem.getItemId() != 0)
|
||||
onExit();
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -126,6 +133,7 @@ class EditorTextActionModeStarter implements CodeEditor.EditorTextActionPresente
|
||||
int column = IntPair.getSecond(packed);
|
||||
mEditor.setSelection(line, column);
|
||||
mEditor.hideAutoCompleteWindow();
|
||||
mEditor.hideDiagnosticWindow();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -0,0 +1,10 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportHeight="24"
|
||||
android:viewportWidth="24">
|
||||
<path
|
||||
android:fillColor="#ffffff"
|
||||
android:pathData="M9.5,3A6.5,6.5 0,0 1,16 9.5C16,11.11 15.41,12.59 14.44,13.73L14.71,14H15.5L20.5,19L19,20.5L14,15.5V14.71L13.73,14.44C12.59,15.41 11.11,16 9.5,16A6.5,6.5 0,0 1,3 9.5A6.5,6.5 0,0 1,9.5 3M9.5,5C7,5 5,7 5,9.5C5,12 7,14 9.5,14C12,14 14,12 14,9.5C14,7 12,5 9.5,5Z"/>
|
||||
</vector>
|
||||
@@ -145,6 +145,23 @@
|
||||
app:iconTint="@color/primaryIconColor"
|
||||
app:cornerRadius="0dp"
|
||||
app:icon="@drawable/ic_diagnostics"
|
||||
app:backgroundTint="@color/primaryColor"
|
||||
app:rippleColor="@color/rippleHighlightColor_light"/>
|
||||
|
||||
<com.google.android.material.button.MaterialButton
|
||||
style="@style/Widget.MaterialComponents.Button.UnelevatedButton"
|
||||
android:id="@+id/view_search_results"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="52dp"
|
||||
android:gravity="start|center_vertical"
|
||||
android:insetTop="0dp"
|
||||
android:insetBottom="0dp"
|
||||
android:text="@string/view_search_results"
|
||||
android:layout_marginBottom="1dp"
|
||||
android:textColor="@color/primaryTextColor"
|
||||
app:iconTint="@color/primaryIconColor"
|
||||
app:cornerRadius="0dp"
|
||||
app:icon="@drawable/ic_search"
|
||||
app:backgroundTint="@color/primaryColor"
|
||||
app:rippleColor="@color/rippleHighlightColor_light"/>
|
||||
|
||||
@@ -292,6 +309,36 @@
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:orientation="vertical"
|
||||
android:id="@+id/searchResultsContainer"
|
||||
android:visibility="gone"
|
||||
android:background="@color/primaryDarkColor"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="0dp"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent">
|
||||
|
||||
<com.google.android.material.appbar.MaterialToolbar
|
||||
android:layout_height="56dp"
|
||||
android:layout_width="match_parent"
|
||||
android:id="@+id/searchResultsToolbar"
|
||||
android:elevation="8dp"
|
||||
android:background="@color/primaryDarkColor"
|
||||
app:title="@string/view_search_results"
|
||||
app:navigationIcon="@drawable/ic_chevron_down"
|
||||
app:navigationIconTint="@color/primaryIconColor"/>
|
||||
|
||||
<LinearLayout
|
||||
android:orientation="vertical"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:id="@+id/searchResultsListContainer"/>
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/symbolText"
|
||||
android:layout_height="wrap_content"
|
||||
@@ -351,4 +398,3 @@
|
||||
</com.google.android.material.navigation.NavigationView>
|
||||
|
||||
</androidx.drawerlayout.widget.DrawerLayout>
|
||||
|
||||
|
||||
@@ -18,7 +18,7 @@
|
||||
android:ellipsize="end"
|
||||
android:textColor="@color/primaryTextColor"
|
||||
android:elevation="0dp"
|
||||
android:background="@android:color/transparent"
|
||||
android:background="@color/primaryDarkColor"
|
||||
app:rippleColor="@color/rippleHighlightColor"
|
||||
app:icon="@drawable/ic_chevron_down"
|
||||
app:iconPadding="8dp"
|
||||
|
||||
@@ -1,4 +1,7 @@
|
||||
<resources xmlns:tools="http://schemas.android.com/tools">
|
||||
<string name="view_search_results">Search results</string>
|
||||
<string name="msg_no_definition">Definition not found</string>
|
||||
<string name="msg_no_references">No references found</string>
|
||||
<string name="license_jdk">AndroidIDE uses a modified build of the JDK which is licensed under the GNU General Public License v2.0. The source code and the license of the JDK can be found in the JDK itself or at : </string>
|
||||
<string name="title_developers">Developers</string>
|
||||
<string name="msg_developers">\u2022 Akash Yadav\n\u2022 Marvin Stelter</string>
|
||||
|
||||
@@ -2,6 +2,7 @@ package com.itsaky.lsp;
|
||||
|
||||
import com.google.gson.JsonElement;
|
||||
import java.io.File;
|
||||
import java.util.List;
|
||||
|
||||
public interface LanguageClient {
|
||||
void javaProgressStart(JavaStartProgressParams params);
|
||||
@@ -9,6 +10,9 @@ public interface LanguageClient {
|
||||
void javaProgressEnd();
|
||||
|
||||
void publishDiagnostics(PublishDiagnosticsParams params);
|
||||
|
||||
void gotoDefinition(List<Location> locations);
|
||||
void references(List<Location> references);
|
||||
void signatureHelp(SignatureHelp signature, File file);
|
||||
void javaColors(JavaColors colors);
|
||||
|
||||
|
||||
@@ -2,6 +2,7 @@ package com.itsaky.lsp;
|
||||
|
||||
import com.google.gson.annotations.SerializedName;
|
||||
import java.net.URI;
|
||||
import com.google.gson.GsonBuilder;
|
||||
|
||||
public class Location {
|
||||
@SerializedName("uri")
|
||||
@@ -17,5 +18,10 @@ public class Location {
|
||||
this.range = range;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return new GsonBuilder().setPrettyPrinting().create().toJson(this);
|
||||
}
|
||||
|
||||
public static final Location NONE = new Location(null, Range.NONE);
|
||||
}
|
||||
|
||||
@@ -31,6 +31,10 @@ public class Range {
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public static Range ofZero() {
|
||||
return new Range(new Position(0, 0), new Position(0, 0));
|
||||
}
|
||||
|
||||
public static final Range NONE = new Range(Position.NONE, Position.NONE);
|
||||
}
|
||||
|
||||
@@ -6,4 +6,10 @@ public class ReferenceContext {
|
||||
|
||||
@SerializedName("includeDeclaration")
|
||||
public boolean includeDeclaration;
|
||||
|
||||
public ReferenceContext(){}
|
||||
|
||||
public ReferenceContext(boolean includeDeclaration) {
|
||||
this.includeDeclaration = includeDeclaration;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user