mirror of
https://gitee.com/zhangsken/AndroidIDE.git
synced 2026-10-16 07:49:44 +08:00
Show quickfixes when diagnostic is selected
This commit is contained in:
Binary file not shown.
@@ -856,8 +856,8 @@ public class EditorActivity extends StudioActivity implements FileTreeFragment.F
|
||||
}
|
||||
|
||||
@Override
|
||||
public void openFile(File file) {
|
||||
openFile(file, null);
|
||||
public EditorFragment openFile(File file) {
|
||||
return openFile(file, null);
|
||||
}
|
||||
|
||||
public EditorFragment openFile(File file, org.eclipse.lsp4j.Range selection) {
|
||||
@@ -865,7 +865,11 @@ public class EditorActivity extends StudioActivity implements FileTreeFragment.F
|
||||
int i = mPagerAdapter.openFile(file, selection, this);
|
||||
if(i >= 0 && !mBinding.tabs.getTabAt(i).isSelected())
|
||||
mBinding.tabs.getTabAt(i).select();
|
||||
mBinding.editorDrawerLayout.closeDrawer(GravityCompat.END);
|
||||
|
||||
if(mBinding.editorDrawerLayout.isDrawerOpen(GravityCompat.END)) {
|
||||
mBinding.editorDrawerLayout.closeDrawer(GravityCompat.END);
|
||||
}
|
||||
|
||||
invalidateOptionsMenu();
|
||||
try {
|
||||
return mPagerAdapter.getFrag(i);
|
||||
|
||||
@@ -214,7 +214,7 @@ public class FileTreeFragment extends BottomSheetDialogFragment implements TreeN
|
||||
}
|
||||
|
||||
public interface FileActionListener {
|
||||
public void openFile(File file);
|
||||
public EditorFragment openFile(File file);
|
||||
public void showFileOptions(File file, TreeNode node);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,16 +16,20 @@ import com.itsaky.androidide.EditorActivity;
|
||||
import com.itsaky.androidide.R;
|
||||
import com.itsaky.androidide.adapters.DiagnosticsAdapter;
|
||||
import com.itsaky.androidide.adapters.SearchListAdapter;
|
||||
import com.itsaky.androidide.app.StudioApp;
|
||||
import com.itsaky.androidide.databinding.LayoutDiagnosticInfoBinding;
|
||||
import com.itsaky.androidide.fragments.EditorFragment;
|
||||
import com.itsaky.androidide.fragments.sheets.ProgressSheet;
|
||||
import com.itsaky.androidide.interfaces.EditorActivityProvider;
|
||||
import com.itsaky.androidide.models.DiagnosticGroup;
|
||||
import com.itsaky.androidide.models.SearchResult;
|
||||
import com.itsaky.androidide.tasks.TaskExecutor;
|
||||
import com.itsaky.androidide.utils.LSPUtils;
|
||||
import com.itsaky.androidide.utils.Logger;
|
||||
import com.itsaky.lsp.SemanticHighlight;
|
||||
import com.itsaky.lsp.services.IDELanguageClient;
|
||||
import com.itsaky.lsp.services.IDELanguageServer;
|
||||
import com.itsaky.toaster.Toaster;
|
||||
import io.github.rosemoe.editor.text.Content;
|
||||
import io.github.rosemoe.editor.widget.CodeEditor;
|
||||
import java.io.File;
|
||||
@@ -37,7 +41,6 @@ import java.util.Map;
|
||||
import java.util.stream.Collectors;
|
||||
import java9.util.concurrent.CompletableFuture;
|
||||
import org.eclipse.lsp4j.CodeAction;
|
||||
import org.eclipse.lsp4j.Command;
|
||||
import org.eclipse.lsp4j.Diagnostic;
|
||||
import org.eclipse.lsp4j.Location;
|
||||
import org.eclipse.lsp4j.LocationLink;
|
||||
@@ -51,8 +54,7 @@ import org.eclipse.lsp4j.ShowDocumentParams;
|
||||
import org.eclipse.lsp4j.ShowDocumentResult;
|
||||
import org.eclipse.lsp4j.SignatureHelp;
|
||||
import org.eclipse.lsp4j.SignatureInformation;
|
||||
import org.eclipse.lsp4j.jsonrpc.messages.Either;
|
||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder;
|
||||
import org.eclipse.lsp4j.TextEdit;
|
||||
|
||||
/**
|
||||
* AndroidIDE specific implementation of the LanguageClient
|
||||
@@ -341,9 +343,43 @@ public abstract class AbstractLanguageClient implements IDELanguageClient {
|
||||
.collect(Collectors.toList())
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Perform the given {@link CodeAction}
|
||||
*
|
||||
* @param editor The {@link CodeEditor} that invoked the code action request.
|
||||
* This is required to reduce the time finding the code action from the edits.
|
||||
* @param action The action to perform
|
||||
*/
|
||||
public void performCodeAction(CodeEditor editor, CodeAction action) {
|
||||
if(activity() == null || editor == null || action == null) {
|
||||
StudioApp.getInstance().toast(R.string.msg_cannot_perform_fix, Toaster.Type.ERROR);
|
||||
return;
|
||||
}
|
||||
|
||||
final ProgressSheet progress = new ProgressSheet();
|
||||
progress.setSubMessageEnabled(false);
|
||||
progress.setWelcomeTextEnabled(false);
|
||||
progress.setCancelable(false);
|
||||
progress.setMessage(activity().getString(R.string.msg_performing_fixes));
|
||||
progress.show(activity().getSupportFragmentManager(), "quick_fix_progress");
|
||||
|
||||
new TaskExecutor().executeAsyncProvideError(() -> performCodeActionAsync(editor, action), (a, b) -> {
|
||||
final Boolean complete = a;
|
||||
final Throwable error = b;
|
||||
|
||||
progress.dismiss();
|
||||
|
||||
if(complete == null || error != null || !complete.booleanValue()) {
|
||||
StudioApp.getInstance().toast(R.string.msg_cannot_perform_fix, Toaster.Type.ERROR);
|
||||
LOG.error("Quickfix error", error);
|
||||
return;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Usually called by {@link io.github.rosemoe.editor.widget.CodeEditor CodeEditor} to show a specific document in EditorActivity and select the specified range
|
||||
* Usually called {@link CodeEditor} to show a specific document in EditorActivity and select the specified range
|
||||
*/
|
||||
@Override
|
||||
public CompletableFuture<ShowDocumentResult> showDocument(ShowDocumentParams params) {
|
||||
@@ -425,6 +461,58 @@ public abstract class AbstractLanguageClient implements IDELanguageClient {
|
||||
return groups;
|
||||
}
|
||||
|
||||
private Boolean performCodeActionAsync(final CodeEditor editor, final CodeAction action) {
|
||||
final Map <String, List<TextEdit>> edits = action.getEdit().getChanges();
|
||||
if(edits == null || edits.isEmpty()) {
|
||||
return Boolean.FALSE;
|
||||
}
|
||||
|
||||
for(Map.Entry<String, List<TextEdit>> entry : edits.entrySet()) {
|
||||
final File file = new File(URI.create(entry.getKey()));
|
||||
if(!file.exists()) continue;
|
||||
|
||||
for(TextEdit edit : entry.getValue()) {
|
||||
final String editorFilepath = editor.getFile() == null ? "" : editor.getFile().getAbsolutePath();
|
||||
if(file.getAbsolutePath().equals(editorFilepath)) {
|
||||
// Edit is in the same editor which requested the code action
|
||||
editInEditor(editor, edit);
|
||||
} else {
|
||||
EditorFragment openedFrag = activity().getPagerAdapter().findEditorByFile(file);
|
||||
|
||||
if(openedFrag != null && openedFrag.getEditor() != null) {
|
||||
// Edit is in another 'opened' file
|
||||
editInEditor(openedFrag.getEditor(), edit);
|
||||
} else {
|
||||
// Edit is in some other file which is not opened
|
||||
// We should open that file and perform the edit
|
||||
openedFrag = activity().openFile(file);
|
||||
if(openedFrag != null && openedFrag.getEditor() != null) {
|
||||
editInEditor(openedFrag.getEditor(), edit);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return Boolean.TRUE;
|
||||
}
|
||||
|
||||
private void editInEditor (final CodeEditor editor, final TextEdit edit) {
|
||||
final Range range = edit.getRange();
|
||||
final int startLine = range.getStart().getLine();
|
||||
final int startCol = range.getStart().getCharacter();
|
||||
final int endLine = range.getEnd().getLine();
|
||||
final int endCol = range.getEnd().getCharacter();
|
||||
|
||||
activity().runOnUiThread(() -> {
|
||||
if(startLine == endLine && startCol == endCol) {
|
||||
editor.getText().insert(startLine, startCol, edit.getNewText());
|
||||
} else {
|
||||
editor.getText().replace(startLine, startCol, endLine, endCol, edit.getNewText());
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public DiagnosticsAdapter newDiagnosticsAdapter() {
|
||||
return new DiagnosticsAdapter(mapAsGroup(this.diagnostics), activity());
|
||||
}
|
||||
|
||||
@@ -157,7 +157,7 @@ public class BinaryHeap {
|
||||
public void update(int id, int newValue) {
|
||||
int position = idToPosition.get(id, 0);
|
||||
if (position == 0) {
|
||||
throw new IllegalArgumentException("trying to update with an invalid id");
|
||||
return;
|
||||
}
|
||||
int origin = nodes[position].data;
|
||||
nodes[position].data = newValue;
|
||||
@@ -177,7 +177,7 @@ public class BinaryHeap {
|
||||
public void remove(int id) {
|
||||
int position = idToPosition.get(id, 0);
|
||||
if (position == 0) {
|
||||
throw new IllegalArgumentException("trying to remove with an invalid id");
|
||||
return;
|
||||
}
|
||||
idToPosition.delete(id);
|
||||
//Replace removed node with last node
|
||||
|
||||
@@ -876,6 +876,15 @@ public class CodeEditor extends View implements ContentListener, TextAnalyzer.Ca
|
||||
return mLanguageServer;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the language client attached to this Editor
|
||||
*
|
||||
* @return The language client currently attached
|
||||
*/
|
||||
public AbstractLanguageClient getLanguageClient() {
|
||||
return mLanguageClient;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets up this editor according to the capabilities of the current language server
|
||||
*/
|
||||
@@ -4835,7 +4844,7 @@ public class CodeEditor extends View implements ContentListener, TextAnalyzer.Ca
|
||||
* @return A {@link CompletableFuture}. May return {@code null}.
|
||||
*/
|
||||
public CompletableFuture<List<Either<Command, CodeAction>>> requestCodeActions() {
|
||||
if(mLanguageServer == null && mLanguageClient == null) return null;
|
||||
if(mLanguageServer == null || mLanguageClient == null) return null;
|
||||
|
||||
final List<Diagnostic> diagnostics = findDiagnosticsContainingLine(getCursor().getLeftLine());
|
||||
return mCodeActionProvider.codeActions(mLanguageServer, getDocumentIdentifier(), getCursorRange(), diagnostics);
|
||||
|
||||
+250
-126
@@ -22,11 +22,27 @@ import android.graphics.drawable.Drawable;
|
||||
import android.view.Menu;
|
||||
import android.view.MenuItem;
|
||||
import android.view.MotionEvent;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.BaseAdapter;
|
||||
import android.widget.ListView;
|
||||
import androidx.appcompat.app.AppCompatActivity;
|
||||
import androidx.appcompat.view.ActionMode;
|
||||
import androidx.appcompat.view.menu.MenuBuilder;
|
||||
import androidx.core.content.ContextCompat;
|
||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder;
|
||||
import com.itsaky.androidide.app.StudioApp;
|
||||
import com.itsaky.toaster.Toaster;
|
||||
import io.github.rosemoe.editor.util.IntPair;
|
||||
import java.util.List;
|
||||
import java9.util.concurrent.CompletableFuture;
|
||||
import org.eclipse.lsp4j.CodeAction;
|
||||
import org.eclipse.lsp4j.Command;
|
||||
import org.eclipse.lsp4j.jsonrpc.messages.Either;
|
||||
import android.view.View;
|
||||
import android.widget.TextView;
|
||||
import com.blankj.utilcode.util.SizeUtils;
|
||||
import java.util.stream.Collectors;
|
||||
import android.view.Gravity;
|
||||
|
||||
/**
|
||||
* Action Mode style text action panel for editor
|
||||
@@ -41,7 +57,7 @@ class EditorTextActionModeStarter implements CodeEditor.EditorTextActionPresente
|
||||
EditorTextActionModeStarter(CodeEditor editor) {
|
||||
mEditor = editor;
|
||||
}
|
||||
|
||||
|
||||
@SuppressLint("RestrictedApi")
|
||||
@Override
|
||||
public void onBeginTextSelect() {
|
||||
@@ -49,145 +65,253 @@ class EditorTextActionModeStarter implements CodeEditor.EditorTextActionPresente
|
||||
return;
|
||||
}
|
||||
mActionMode = ((AppCompatActivity) mEditor.getContext()).startSupportActionMode(new ActionMode.Callback() {
|
||||
|
||||
@Override
|
||||
public boolean onCreateActionMode(ActionMode actionMode, Menu menu) {
|
||||
mEditor.mStartedActionMode = CodeEditor.ACTION_MODE_SELECT_TEXT;
|
||||
if(menu instanceof MenuBuilder){
|
||||
MenuBuilder builder = (MenuBuilder) menu;
|
||||
builder.setOptionalIconsVisible(true);
|
||||
}
|
||||
actionMode.setTitle(android.R.string.selectTextMode);
|
||||
TypedArray array = mEditor.getContext().getTheme().obtainStyledAttributes(new int[]{
|
||||
android.R.attr.actionModeSelectAllDrawable,
|
||||
android.R.attr.actionModeCutDrawable,
|
||||
android.R.attr.actionModeCopyDrawable,
|
||||
android.R.attr.actionModePasteDrawable,
|
||||
});
|
||||
|
||||
menu.add(0, 0, 0, mEditor.getContext().getString(android.R.string.selectAll))
|
||||
.setShowAsActionFlags(2)
|
||||
.setIcon(array.getDrawable(0));
|
||||
|
||||
if(mEditor.isEditable()) {
|
||||
menu.add(0, 1, 0, mEditor.getContext().getString(android.R.string.cut))
|
||||
private List<Either<Command, CodeAction>> fixes;
|
||||
|
||||
@Override
|
||||
public boolean onCreateActionMode(ActionMode actionMode, Menu menu) {
|
||||
mEditor.mStartedActionMode = CodeEditor.ACTION_MODE_SELECT_TEXT;
|
||||
if (menu instanceof MenuBuilder) {
|
||||
MenuBuilder builder = (MenuBuilder) menu;
|
||||
builder.setOptionalIconsVisible(true);
|
||||
}
|
||||
actionMode.setTitle(android.R.string.selectTextMode);
|
||||
TypedArray array = mEditor.getContext().getTheme().obtainStyledAttributes(new int[]{
|
||||
android.R.attr.actionModeSelectAllDrawable,
|
||||
android.R.attr.actionModeCutDrawable,
|
||||
android.R.attr.actionModeCopyDrawable,
|
||||
android.R.attr.actionModePasteDrawable,
|
||||
});
|
||||
|
||||
final CompletableFuture<List<Either<Command, CodeAction>>> future = mEditor.requestCodeActions();
|
||||
|
||||
if (future != null) {
|
||||
|
||||
future.whenComplete((a, b) -> {
|
||||
fixes = a;
|
||||
});
|
||||
|
||||
menu.add(0, 8, 0, mEditor.getContext().getString(com.itsaky.androidide.R.string.msg_code_actions))
|
||||
.setShowAsActionFlags(MenuItem.SHOW_AS_ACTION_NEVER)
|
||||
.setIcon(createDrawable(com.itsaky.androidide.R.drawable.ic_quickfix));
|
||||
}
|
||||
|
||||
menu.add(0, 0, 0, mEditor.getContext().getString(android.R.string.selectAll))
|
||||
.setShowAsActionFlags(2)
|
||||
.setIcon(array.getDrawable(1));
|
||||
}
|
||||
.setIcon(array.getDrawable(0));
|
||||
|
||||
menu.add(0, 2, 0, mEditor.getContext().getString(android.R.string.copy))
|
||||
.setShowAsActionFlags(2)
|
||||
.setIcon(array.getDrawable(2));
|
||||
|
||||
if(mEditor.isEditable()) {
|
||||
menu.add(0, 3, 0, mEditor.getContext().getString(android.R.string.paste))
|
||||
if (mEditor.isEditable()) {
|
||||
menu.add(0, 1, 0, mEditor.getContext().getString(android.R.string.cut))
|
||||
.setShowAsActionFlags(2)
|
||||
.setIcon(array.getDrawable(1));
|
||||
}
|
||||
|
||||
menu.add(0, 2, 0, mEditor.getContext().getString(android.R.string.copy))
|
||||
.setShowAsActionFlags(2)
|
||||
.setIcon(array.getDrawable(3));
|
||||
}
|
||||
|
||||
if(mEditor.isGotoDefinitionEnabled()) {
|
||||
menu.add(0, 4, 0, mEditor.getContext().getString(com.itsaky.androidide.R.string.menu_navigate_definition))
|
||||
.setIcon(array.getDrawable(2));
|
||||
|
||||
if (mEditor.isEditable()) {
|
||||
menu.add(0, 3, 0, mEditor.getContext().getString(android.R.string.paste))
|
||||
.setShowAsActionFlags(2)
|
||||
.setIcon(array.getDrawable(3));
|
||||
}
|
||||
|
||||
if (mEditor.isGotoDefinitionEnabled()) {
|
||||
menu.add(0, 4, 0, mEditor.getContext().getString(com.itsaky.androidide.R.string.menu_navigate_definition))
|
||||
.setShowAsActionFlags(1)
|
||||
.setIcon(createDrawable(com.itsaky.androidide.R.drawable.ic_goto_definition));
|
||||
}
|
||||
|
||||
if (mEditor.isFindReferencesEnabled()) {
|
||||
menu.add(0, 5, 0, mEditor.getContext().getString(com.itsaky.androidide.R.string.menu_navigate_references))
|
||||
.setShowAsActionFlags(1)
|
||||
.setIcon(createDrawable(com.itsaky.androidide.R.drawable.ic_find_references));
|
||||
}
|
||||
|
||||
menu.add(0, 6, 0, mEditor.getContext().getString(com.itsaky.androidide.R.string.menu_comment_line))
|
||||
.setShowAsActionFlags(1)
|
||||
.setIcon(createDrawable(com.itsaky.androidide.R.drawable.ic_goto_definition));
|
||||
}
|
||||
|
||||
if(mEditor.isFindReferencesEnabled()) {
|
||||
menu.add(0, 5, 0, mEditor.getContext().getString(com.itsaky.androidide.R.string.menu_navigate_references))
|
||||
.setIcon(createDrawable(com.itsaky.androidide.R.drawable.ic_comment_line));
|
||||
|
||||
menu.add(0, 7, 0, mEditor.getContext().getString(com.itsaky.androidide.R.string.menu_uncomment_line))
|
||||
.setShowAsActionFlags(1)
|
||||
.setIcon(createDrawable( com.itsaky.androidide.R.drawable.ic_find_references));
|
||||
.setIcon(createDrawable(com.itsaky.androidide.R.drawable.ic_uncomment_line));
|
||||
|
||||
array.recycle();
|
||||
return true;
|
||||
}
|
||||
|
||||
private Drawable createDrawable(int icon) {
|
||||
final Drawable d = ContextCompat.getDrawable(mEditor.getContext(), icon);
|
||||
d.setColorFilter(ContextCompat.getColor(mEditor.getContext(), com.itsaky.androidide.R.color.secondaryColor), PorterDuff.Mode.SRC_ATOP);
|
||||
return d;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onPrepareActionMode(ActionMode actionMode, Menu menu) {
|
||||
if (mEditor.getFile() == null) return false;
|
||||
|
||||
final String name = mEditor.getFile().getName();
|
||||
final boolean isJava = name.endsWith(".java") || name.endsWith(".gradle");
|
||||
final boolean isXml = name.endsWith(".xml");
|
||||
final MenuItem def = menu.findItem(4);
|
||||
final MenuItem ref = menu.findItem(5);
|
||||
final MenuItem comment = menu.findItem(6);
|
||||
final MenuItem uncomment = menu.findItem(7);
|
||||
final MenuItem quickfix = menu.findItem(8);
|
||||
|
||||
comment.setEnabled(isJava || isXml).getIcon().setAlpha(isJava || isXml ? 255 : 76);
|
||||
uncomment.setEnabled(isJava || isXml).getIcon().setAlpha(isJava || isXml ? 255 : 76);
|
||||
|
||||
/**
|
||||
* Thesw menu items may, or may not be added
|
||||
* So we need to check if its null or not
|
||||
* before we perform any further actions
|
||||
*/
|
||||
if (def != null) {
|
||||
def.getIcon().setAlpha(isJava ? 255 : 76);
|
||||
def.setVisible(isJava);
|
||||
}
|
||||
|
||||
if (ref != null) {
|
||||
ref.getIcon().setAlpha(isJava ? 255 : 76);
|
||||
ref.setVisible(isJava);
|
||||
}
|
||||
|
||||
if (quickfix != null) {
|
||||
quickfix.getIcon().setAlpha(isJava ? 255 : 76);
|
||||
quickfix.setVisible(isJava && fixes != null && !fixes.isEmpty());
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onActionItemClicked(ActionMode actionMode, MenuItem menuItem) {
|
||||
switch (menuItem.getItemId()) {
|
||||
case 0:
|
||||
mEditor.selectAll();
|
||||
break;
|
||||
case 1:
|
||||
mEditor.cutText();
|
||||
break;
|
||||
case 2:
|
||||
mEditor.copyText();
|
||||
break;
|
||||
case 3:
|
||||
mEditor.pasteText();
|
||||
break;
|
||||
case 4:
|
||||
mEditor.findDefinition();
|
||||
break;
|
||||
case 5:
|
||||
mEditor.findReferences();
|
||||
break;
|
||||
case 6:
|
||||
mEditor.commentLine();
|
||||
break;
|
||||
case 7:
|
||||
mEditor.uncommentLine();
|
||||
break;
|
||||
case 8 :
|
||||
if (fixes == null || fixes.isEmpty()) {
|
||||
StudioApp.getInstance().toast(com.itsaky.androidide.R.string.msg_no_code_actions, Toaster.Type.INFO);
|
||||
break;
|
||||
}
|
||||
showFixes();
|
||||
break;
|
||||
}
|
||||
|
||||
if (menuItem.getItemId() != 0) {
|
||||
onExit();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDestroyActionMode(ActionMode actionMode) {
|
||||
mEditor.mStartedActionMode = CodeEditor.ACTION_MODE_NONE;
|
||||
mActionMode = null;
|
||||
mEditor.setSelection(mEditor.getCursor().getLeftLine(), mEditor.getCursor().getLeftColumn());
|
||||
}
|
||||
|
||||
void showFixes() {
|
||||
final MaterialAlertDialogBuilder builder = new MaterialAlertDialogBuilder(mEditor.getContext(), com.itsaky.androidide.R.style.AppTheme_MaterialAlertDialog);
|
||||
builder.setTitle(com.itsaky.androidide.R.string.msg_code_actions);
|
||||
builder.setView(createFixesListView());
|
||||
builder.show();
|
||||
}
|
||||
|
||||
ListView createFixesListView() {
|
||||
final ListView list = new ListView(mEditor.getContext());
|
||||
final QuickFixAdapter adapter = new QuickFixAdapter(
|
||||
fixes.stream()
|
||||
.filter(e -> e != null && e.isRight())
|
||||
.map(e -> e.getRight())
|
||||
.collect(Collectors.toList())
|
||||
);
|
||||
list.setLayoutParams(new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT));
|
||||
list.setAdapter(adapter);
|
||||
list.setOnItemClickListener((a, b, c, d) -> {
|
||||
performCodeAction(adapter.getItem(c));
|
||||
});
|
||||
return list;
|
||||
}
|
||||
|
||||
class QuickFixAdapter extends BaseAdapter {
|
||||
|
||||
menu.add(0, 6, 0, mEditor.getContext().getString(com.itsaky.androidide.R.string.menu_comment_line))
|
||||
.setShowAsActionFlags(1)
|
||||
.setIcon(createDrawable( com.itsaky.androidide.R.drawable.ic_comment_line));
|
||||
private final List<CodeAction> actions;
|
||||
private final int dp16 = SizeUtils.dp2px(16);
|
||||
private final int dp4 = SizeUtils.dp2px(4);
|
||||
private final int dp48 = SizeUtils.dp2px(48);
|
||||
|
||||
menu.add(0, 7, 0, mEditor.getContext().getString(com.itsaky.androidide.R.string.menu_uncomment_line))
|
||||
.setShowAsActionFlags(1)
|
||||
.setIcon(createDrawable( com.itsaky.androidide.R.drawable.ic_uncomment_line));
|
||||
|
||||
array.recycle();
|
||||
return true;
|
||||
}
|
||||
|
||||
private Drawable createDrawable(int icon) {
|
||||
final Drawable d = ContextCompat.getDrawable(mEditor.getContext(), icon);
|
||||
d.setColorFilter(ContextCompat.getColor(mEditor.getContext(), com.itsaky.androidide.R.color.secondaryColor), PorterDuff.Mode.SRC_ATOP);
|
||||
return d;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onPrepareActionMode(ActionMode actionMode, Menu menu) {
|
||||
if(mEditor.getFile() == null) return false;
|
||||
|
||||
final String name = mEditor.getFile().getName();
|
||||
final boolean isJava = name.endsWith(".java") || name.endsWith(".gradle");
|
||||
final boolean isXml = name.endsWith(".xml");
|
||||
final MenuItem def = menu.findItem(4);
|
||||
final MenuItem ref = menu.findItem(5);
|
||||
final MenuItem comment = menu.findItem(6);
|
||||
final MenuItem uncomment = menu.findItem(7);
|
||||
|
||||
comment.setEnabled(isJava || isXml).getIcon().setAlpha(isJava || isXml ? 255 : 76);
|
||||
uncomment.setEnabled(isJava || isXml).getIcon().setAlpha(isJava || isXml ? 255 : 76);
|
||||
|
||||
/**
|
||||
* Thesw menu items may, or may not be added
|
||||
* So we need to check if its null or not
|
||||
* before we perform any further actions
|
||||
*/
|
||||
if(def != null) {
|
||||
def.setEnabled(isJava).getIcon().setAlpha(isJava ? 255 : 76);
|
||||
}
|
||||
|
||||
if(ref != null) {
|
||||
ref.setEnabled(isJava).getIcon().setAlpha(isJava ? 255 : 76);
|
||||
}
|
||||
public QuickFixAdapter(List<CodeAction> actions) {
|
||||
this.actions = actions;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
@Override
|
||||
public int getCount() {
|
||||
return actions.size();
|
||||
}
|
||||
|
||||
@Override
|
||||
public CodeAction getItem(int position) {
|
||||
return actions.get(position);
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getItemId(int position) {
|
||||
return position;
|
||||
}
|
||||
|
||||
@Override
|
||||
public View getView(int position, View convertView, ViewGroup parent) {
|
||||
if(convertView == null) {
|
||||
convertView = createItemTextView(position, parent);
|
||||
}
|
||||
return convertView;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onActionItemClicked(ActionMode actionMode, MenuItem menuItem) {
|
||||
switch (menuItem.getItemId()) {
|
||||
case 0:
|
||||
mEditor.selectAll();
|
||||
break;
|
||||
case 1:
|
||||
mEditor.cutText();
|
||||
break;
|
||||
case 2:
|
||||
mEditor.copyText();
|
||||
break;
|
||||
case 3:
|
||||
mEditor.pasteText();
|
||||
break;
|
||||
case 4:
|
||||
mEditor.findDefinition();
|
||||
break;
|
||||
case 5:
|
||||
mEditor.findReferences();
|
||||
break;
|
||||
case 6:
|
||||
mEditor.commentLine();
|
||||
break;
|
||||
case 7:
|
||||
mEditor.uncommentLine();
|
||||
break;
|
||||
private View createItemTextView(int position, ViewGroup parent) {
|
||||
final CodeAction action = getItem(position);
|
||||
final TextView text = new TextView(parent.getContext());
|
||||
final String title = action.getTitle();
|
||||
|
||||
text.setText(title);
|
||||
text.setPaddingRelative(dp16, dp4, dp16, dp4);
|
||||
text.setMinHeight(dp48);
|
||||
text.setGravity(Gravity.CENTER_VERTICAL);
|
||||
|
||||
return text;
|
||||
}
|
||||
}
|
||||
if(menuItem.getItemId() != 0) {
|
||||
onExit();
|
||||
|
||||
void performCodeAction(CodeAction action) {
|
||||
if(mEditor.getLanguageClient() != null) {
|
||||
mEditor.getLanguageClient().performCodeAction(mEditor, action);
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDestroyActionMode(ActionMode actionMode) {
|
||||
mEditor.mStartedActionMode = CodeEditor.ACTION_MODE_NONE;
|
||||
mActionMode = null;
|
||||
mEditor.setSelection(mEditor.getCursor().getLeftLine(), mEditor.getCursor().getLeftColumn());
|
||||
}
|
||||
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -1,10 +1,12 @@
|
||||
<resources xmlns:tools="http://schemas.android.com/tools">
|
||||
<string name="title_confirm_changes">Confirm changes</string>
|
||||
<string name="msg_confirm_changes">These files will be modified:\n%s</string>
|
||||
<string name="msg_no_code_actions">No code actions found</string>
|
||||
<string name="msg_no_code_actions">No quickfix found</string>
|
||||
<string name="msg_cannot_perform_fix">Unable to perform quick fix</string>
|
||||
<string name="msg_performing_fixes">Performing fixes…</string>
|
||||
<string name="msg_analyzing_actions">Analyzing code actions</string>
|
||||
<string name="msg_service_not_started">Services has not been started yet</string>
|
||||
<string name="msg_code_actions">Code Actions</string>
|
||||
<string name="msg_code_actions">Quickfixes</string>
|
||||
<string name="msg_api_info_since">Since API %d</string>
|
||||
<string name="msg_api_info_removed">Removed in API %d</string>
|
||||
<string name="msg_api_info_deprecated">Deprecated in API %d</string>
|
||||
|
||||
Reference in New Issue
Block a user