Backup before changing implementation of Terminal

This commit is contained in:
Akash Yadav
2021-10-16 17:57:48 +05:30
parent 0645563a4e
commit 91ce02e2ee
7 changed files with 144 additions and 26 deletions
+1 -4
View File
@@ -24,7 +24,7 @@
android:hardwareAccelerated="true">
<activity
android:name=".SplashActivity"
android:exported="false">
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
@@ -80,8 +80,5 @@
<meta-data
android:name="com.google.firebase.messaging.default_notification_channel_id"
android:value="@string/cms_channel_id_devs" />
<property
android:name="android.media.PROPERTY_MEDIA_CAPABILITIES"
android:resource="@xml/media_capabilities" />
</application>
</manifest>
Binary file not shown.
@@ -34,8 +34,10 @@ import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java9.util.concurrent.CompletableFuture;
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;
@@ -49,6 +51,8 @@ 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;
/**
* AndroidIDE specific implementation of the LanguageClient
@@ -125,6 +129,29 @@ public abstract class AbstractLanguageClient implements IDELanguageClient {
}
}
public void showCodeActions(List<Either<Command, CodeAction>> actions) {
final String[] titles = new String[actions.size()];
int i=0;
for(Either<Command, CodeAction> either : actions) {
if(either.isLeft()) {
titles[i] = "[Command] " + either.getLeft().getTitle();
} else if(either.isRight()) {
titles[i] = "[Action] " + either.getRight().getTitle();
}
++i;
}
final MaterialAlertDialogBuilder builder = new MaterialAlertDialogBuilder(activity(), R.style.AppTheme_MaterialAlertDialog);
builder.setTitle(R.string.msg_code_actions);
builder.setItems(titles, null);
builder.show();
}
public void hideCodeActions() {
if(activity() == null) return;
}
public void showDiagnostic(Diagnostic diagnostic, final CodeEditor editor) {
if(activity() == null || activity().getDiagnosticBinding() == null) {
return;
@@ -429,7 +456,7 @@ public abstract class AbstractLanguageClient implements IDELanguageClient {
public DiagnosticsAdapter newDiagnosticsAdapter() {
return new DiagnosticsAdapter(mapAsGroup(this.diagnostics), activity());
}
/**
* Reports connection progress
*/
@@ -7,8 +7,10 @@ import java.io.Closeable;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;
import java.net.InetSocketAddress;
import java.nio.channels.AsynchronousServerSocketChannel;
import java.nio.channels.AsynchronousSocketChannel;
import java.nio.channels.Channels;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.Future;
@@ -24,7 +26,7 @@ public class LSPClientLauncher extends Thread {
private Future<Void> listeningFuture;
private final AbstractLanguageClient languageClient;
private ServerSocket serverSocket;
private AsynchronousServerSocketChannel serverSocket;
private IDELanguageServer server;
public LSPClientLauncher(AbstractLanguageClient client, int port) {
@@ -54,13 +56,14 @@ public class LSPClientLauncher extends Thread {
public void run() {
try {
languageClient.connectionReport("Starting server socket");
serverSocket = new ServerSocket(PORT);
serverSocket = AsynchronousServerSocketChannel.open();
serverSocket.bind(new InetSocketAddress(PORT));
languageClient.connectionReport("Waiting for server to connect...");
languageClient.startServer();
final Socket server = serverSocket.accept();
final OutputStream outWriter = new OutputStreamWrapper(server.getOutputStream());
final InputStream inReader = server.getInputStream();
final AsynchronousSocketChannel server = serverSocket.accept().get();
final OutputStream outWriter = new OutputStreamWrapper(Channels.newOutputStream(server));
final InputStream inReader = Channels.newInputStream(server);
languageClient.connectionReport("Server connected. Launching client...");
Launcher<IDELanguageServer> launcher = createClientLauncher(languageClient, inReader, outWriter);
@@ -70,13 +73,16 @@ public class LSPClientLauncher extends Thread {
languageClient.onServerConnected(this.server);
languageClient.connectionReport("Server is now listening.");
while (!(listeningFuture.isCancelled() || listeningFuture.isDone())) {
// Take some rest
sleep(50);
try {
LOG.info("Waiting for server connection result");
listeningFuture.get();
LOG.info("listeningFuture.get returned");
} catch (Throwable th) {
LOG.error("listeningFuture.get error", th);
}
// Make sure we close the server. Sockets are limited resources...
CloseUtils.closeIOQuietly(inReader, outWriter, server);
CloseUtils.closeIOQuietly(serverSocket, server, outWriter, inReader);
languageClient.connectionReport("Server disconnected.");
languageClient.onServerDisconnected();
} catch (Throwable th) {
@@ -103,6 +109,9 @@ public class LSPClientLauncher extends Thread {
server.exit();
}
serverSocket.close();
if(listeningFuture != null && !listeningFuture.isDone()) {
listeningFuture.cancel(true);
}
} catch (Throwable th) {
// Ignored
}
@@ -113,15 +122,17 @@ public class LSPClientLauncher extends Thread {
* Writing to a socket's output stream is considered as network operation
* Trying to write to a socket on UI Thread will result in NetworkOnMainThreadExeption
*/
private class OutputStreamWrapper extends OutputStream {
private final AsyncWriter writer;
private final Thread writerThread;
private final OutputStream actualStream;
public OutputStreamWrapper(OutputStream actualStream) {
this.writer = new AsyncWriter(actualStream);
this.writerThread = new Thread(writer);
this.actualStream = actualStream;
this.writerThread.start();
}
@@ -133,11 +144,11 @@ public class LSPClientLauncher extends Thread {
/**
* LSP4J always calls this method to write to server.
* LSP4J always calls this method to write to remote proxy.
* See https://github.com/eclipse/lsp4j/blob/253aef9a702659f2524ecefaab7e829278c2ffd3/org.eclipse.lsp4j.jsonrpc/src/main/java/org/eclipse/lsp4j/jsonrpc/json/StreamMessageConsumer.java#L67
*/
@Override
public void write(byte[] b) throws IOException {
public void write(final byte[] b) throws IOException {
// Do not call super.write(b);
// If done, it will further call write(int)
this.writer.write(b);
@@ -177,7 +188,7 @@ public class LSPClientLauncher extends Thread {
this.out.write(data.data);
this.out.flush();
} catch (Throwable e) {
LOG.error("Error writing to LanguageServer");
LOG.error("Error writing to LanguageServer[closed=" + closed + "]", e);
}
}
@@ -186,8 +197,8 @@ public class LSPClientLauncher extends Thread {
@Override
public void close() throws IOException {
this.closed = true;
this.out.close();
this.closed = true;
}
class Writable {
@@ -0,0 +1,41 @@
package com.itsaky.androidide.lsp.providers;
import com.itsaky.lsp.services.IDELanguageServer;
import java.util.ArrayList;
import java.util.List;
import java9.util.concurrent.CompletableFuture;
import org.eclipse.lsp4j.CodeAction;
import org.eclipse.lsp4j.CodeActionContext;
import org.eclipse.lsp4j.CodeActionParams;
import org.eclipse.lsp4j.Command;
import org.eclipse.lsp4j.Diagnostic;
import org.eclipse.lsp4j.Range;
import org.eclipse.lsp4j.TextDocumentIdentifier;
import org.eclipse.lsp4j.jsonrpc.messages.Either;
/**
* Provides code actions to editor. Handles cancellation of last incomplete request.
*/
public class CodeActionProvider {
private CompletableFuture<List<Either<Command, CodeAction>>> lastRequest;
public CompletableFuture<List<Either<Command, CodeAction>>> codeActions(IDELanguageServer server, TextDocumentIdentifier documentId, Range cursorRange, List<Diagnostic> diagnostics) {
if(lastRequest != null && !lastRequest.isDone()) {
lastRequest.cancel(true);
}
if(server == null || cursorRange == null || documentId == null)
return null;
final CodeActionParams params = new CodeActionParams();
final CodeActionContext context = new CodeActionContext();
context.setDiagnostics(diagnostics == null ? new ArrayList<Diagnostic>() : diagnostics);
params.setContext(context);
params.setTextDocument(documentId);
params.setRange(cursorRange);
return lastRequest = server.getTextDocumentService().codeAction(params);
}
}
@@ -67,6 +67,7 @@ import com.itsaky.androidide.app.StudioApp;
import com.itsaky.androidide.databinding.LayoutDialogTextInputBinding;
import com.itsaky.androidide.lsp.AbstractLanguageClient;
import com.itsaky.androidide.lsp.LSPProvider;
import com.itsaky.androidide.lsp.providers.CodeActionProvider;
import com.itsaky.androidide.syntax.colorschemes.SchemeAndroidIDE;
import com.itsaky.androidide.utils.Logger;
import com.itsaky.androidide.utils.Symbols;
@@ -103,7 +104,9 @@ import java.util.List;
import java.util.Map;
import java.util.Set;
import java9.util.concurrent.CompletableFuture;
import org.eclipse.lsp4j.CodeAction;
import org.eclipse.lsp4j.CodeActionOptions;
import org.eclipse.lsp4j.Command;
import org.eclipse.lsp4j.CompletionOptions;
import org.eclipse.lsp4j.DefinitionOptions;
import org.eclipse.lsp4j.DefinitionParams;
@@ -276,6 +279,7 @@ public class CodeEditor extends View implements ContentListener, TextAnalyzer.Ca
private EditorLanguage mLanguage;
private IDELanguageServer mLanguageServer;
private AbstractLanguageClient mLanguageClient;
private CodeActionProvider mCodeActionProvider;
private long mLastMakeVisible = 0;
private EditorAutoCompleteWindow mCompletionWindow;
private EditorTouchEventHandler mEventHandler;
@@ -560,6 +564,7 @@ public class CodeEditor extends View implements ContentListener, TextAnalyzer.Ca
setFocusableInTouchMode(true);
mConnection = new EditorInputConnection(this);
mCompletionWindow = new EditorAutoCompleteWindow(this);
mCodeActionProvider = new CodeActionProvider();
mVerticalEdgeGlow = new MaterialEdgeEffect();
mHorizontalGlow = new MaterialEdgeEffect();
@@ -1478,7 +1483,7 @@ public class CodeEditor extends View implements ContentListener, TextAnalyzer.Ca
drawWhitespaces(canvas, paintingOffset, row, firstVisibleChar, lastVisibleChar, trailingWhitespaceStart, columnCount, circleRadius);
}
}
// Draw composing text underline
if (line == mConnection.mComposingLine) {
int composingStart = mConnection.mComposingStart;
@@ -4820,10 +4825,47 @@ public class CodeEditor extends View implements ContentListener, TextAnalyzer.Ca
}
}
/**
* Request code actions from server at the given position containing given diagnostics
* <p>
* Called by {@link EditorTouchEventHandler}
* <p>
* TODO The current implementation in JLS does not work. Make it work!
*/
public void requestCodeActions() {
if(mLanguageServer == null && mLanguageClient == null) return;
final List<Diagnostic> diagnostics = findDiagnosticsContainingLine(getCursor().getLeftLine());
final CompletableFuture<List<Either<Command, CodeAction>>> future = mCodeActionProvider.codeActions(mLanguageServer, getDocumentIdentifier(), getCursorRange(), diagnostics);
if(future == null) {
return;
}
future.whenComplete((l, t) -> {
final List<Either<Command, CodeAction>> actions = l;
final Throwable th = t;
if(future.isCancelled() || future.isCompletedExceptionally() || actions == null || actions.isEmpty()) {
mLanguageClient.hideCodeActions();
return;
}
mLanguageClient.showCodeActions(actions);
});
}
public Position getCursorAsLSPPosition() {
return new Position(getCursor().getLeftLine(), getCursor().getLeftColumn());
}
public Range getCursorRange() {
final Cursor cursor = getCursor();
final Position start = new Position(cursor.getLeftLine(), cursor.getLeftColumn());
final Position end = new Position(cursor.getRightLine(), cursor.getRightColumn());
return new Range(start, end);
}
public TextDocumentIdentifier getDocumentIdentifier() {
return new TextDocumentIdentifier(getFile().toURI().toString());
}
@@ -48,15 +48,15 @@
android:layout_below="@id/item"
android:paddingStart="16dp"
android:clipChildren="false"
android:clipToPadding="false"
tools:ignore="ScrollViewSize">
android:clipToPadding="false">
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/items"
android:layout_height="wrap_content"
android:layout_width="match_parent"
android:paddingStart="8dp"
android:paddingEnd="8dp"/>
android:paddingEnd="8dp"
tools:ignore="ScrollViewSize"/>
</HorizontalScrollView>