Append newline in String literals in Java and Groovy

This commit is contained in:
Akash Yadav
2021-10-27 12:54:45 +05:30
parent 0855ab1918
commit b2db9992fb
17 changed files with 278 additions and 45 deletions
@@ -193,8 +193,6 @@ public class EditorActivity extends StudioActivity implements FileTreeFragment.F
mBinding.tabs.setupWithViewPager(mBinding.editorViewPager); mBinding.tabs.setupWithViewPager(mBinding.editorViewPager);
mBinding.tabs.setOnTabSelectedListener(this); mBinding.tabs.setOnTabSelectedListener(this);
mBinding.fabView.setOnClickListener(v -> showViewOptions()); mBinding.fabView.setOnClickListener(v -> showViewOptions());
// mBinding.diagnosticTextContainer.setVisibility(View.GONE);
// mBinding.diagnosticText.setClickable(false);
createQuickActions(); createQuickActions();
@@ -705,6 +703,8 @@ public class EditorActivity extends StudioActivity implements FileTreeFragment.F
startActivity(IntentUtils.getShareTextIntent(getString(R.string.msg_share_app))); startActivity(IntentUtils.getShareTextIntent(getString(R.string.msg_share_app)));
} else if(id == R.id.editornav_close_project) { } else if(id == R.id.editornav_close_project) {
confirmProjectClose(); confirmProjectClose();
} else if (id == R.id.editornav_terminal) {
openTerminal();
} }
mBinding.getRoot().closeDrawer(GravityCompat.START); mBinding.getRoot().closeDrawer(GravityCompat.START);
return false; return false;
@@ -1004,6 +1004,12 @@ public class EditorActivity extends StudioActivity implements FileTreeFragment.F
////////////// PRIVATE APIS ///////////////////// ////////////// PRIVATE APIS /////////////////////
///////////////////////////////////////////////// /////////////////////////////////////////////////
private void openTerminal () {
final Intent intent = new Intent(this, TerminalActivity.class);
intent.putExtra(TerminalActivity.KEY_WORKING_DIRECTORY, mProject.getProjectPath());
startActivity(intent);
}
private void startLanguageServers() { private void startLanguageServers() {
LSP.setActivityProvider(this); LSP.setActivityProvider(this);
LSP.Java.start(() -> { LSP.Java.start(() -> {
@@ -28,6 +28,7 @@ import com.itsaky.terminal.view.TerminalView;
import com.itsaky.terminal.view.TerminalViewClient; import com.itsaky.terminal.view.TerminalViewClient;
import java.util.Map; import java.util.Map;
import org.json.JSONException; import org.json.JSONException;
import android.os.Bundle;
public class TerminalActivity extends StudioActivity { public class TerminalActivity extends StudioActivity {
@@ -42,12 +43,14 @@ public class TerminalActivity extends StudioActivity {
private final Client client = new Client(); private final Client client = new Client();
private static final Logger LOG = Logger.instance("TerminalActivity"); private static final Logger LOG = Logger.instance("TerminalActivity");
public static final String KEY_WORKING_DIRECTORY = "terminal_workingDirectory";
@Override @Override
protected View bindLayout() { protected View bindLayout() {
binding = ActivityTerminalBinding.inflate(getLayoutInflater()); binding = ActivityTerminalBinding.inflate(getLayoutInflater());
terminal = new TerminalView(this, null); terminal = new TerminalView(this, null);
terminal.setTerminalViewClient(client); terminal.setTerminalViewClient(client);
terminal.attachSession(createSession()); terminal.attachSession(createSession(getWorkingDirectory()));
terminal.setKeepScreenOn(true); terminal.setKeepScreenOn(true);
terminal.setTextSize(currentTextSize = SizeUtils.dp2px(10)); terminal.setTextSize(currentTextSize = SizeUtils.dp2px(10));
terminal.setTypeface(TypefaceUtils.jetbrainsMono()); terminal.setTypeface(TypefaceUtils.jetbrainsMono());
@@ -65,6 +68,18 @@ public class TerminalActivity extends StudioActivity {
return binding.getRoot(); return binding.getRoot();
} }
private String getWorkingDirectory() {
final Bundle extras = getIntent().getExtras();
if(extras != null && extras.containsKey(KEY_WORKING_DIRECTORY)) {
String directory = extras.getString(KEY_WORKING_DIRECTORY, null);
if(directory == null || directory.trim().length() <= 0) {
directory = Environment.HOME.getAbsolutePath();
}
return directory;
}
return Environment.HOME.getAbsolutePath();
}
private KeyListener getKeyListener() { private KeyListener getKeyListener() {
return listener == null ? listener = new KeyListener(terminal) : listener; return listener == null ? listener = new KeyListener(terminal) : listener;
@@ -99,7 +114,7 @@ public class TerminalActivity extends StudioActivity {
} }
} }
private TerminalSession createSession() { private TerminalSession createSession(final String workingDirectory) {
final Map<String, String> envs = Environment.getEnvironment(true); final Map<String, String> envs = Environment.getEnvironment(true);
final String[] env = new String[envs.size()]; final String[] env = new String[envs.size()];
int i=0; int i=0;
@@ -110,7 +125,7 @@ public class TerminalActivity extends StudioActivity {
session = new TerminalSession( session = new TerminalSession(
Environment.SHELL.getAbsolutePath(), // Shell command Environment.SHELL.getAbsolutePath(), // Shell command
Environment.HOME.getAbsolutePath(), // Working directory workingDirectory, // Working directory
new String[]{}, // Arguments new String[]{}, // Arguments
env, // Environment variables env, // Environment variables
TerminalEmulator.DEFAULT_TERMINAL_TRANSCRIPT_ROWS, // Transcript rows TerminalEmulator.DEFAULT_TERMINAL_TRANSCRIPT_ROWS, // Transcript rows
@@ -62,17 +62,11 @@ public class CompletionListAdapter extends EditorCompletionAdapter {
showApiInfoIfNeeded(item, binding.completionApiInfo); showApiInfoIfNeeded(item, binding.completionApiInfo);
final ViewTreeObserver.OnGlobalLayoutListener listener = new ViewTreeObserver.OnGlobalLayoutListener(){ binding.getRoot().getViewTreeObserver().addOnGlobalLayoutListener(() -> {
ViewGroup.LayoutParams p = binding.completionIconText.getLayoutParams();
@Override p.height = binding.getRoot().getHeight();
public void onGlobalLayout() { binding.completionIconText.setLayoutParams(p);
binding.getRoot().getViewTreeObserver().removeOnGlobalLayoutListener(this); });
ViewGroup.LayoutParams p = binding.completionIconText.getLayoutParams();
p.height = binding.getRoot().getHeight();
binding.completionIconText.setLayoutParams(p);
}
};
binding.getRoot().getViewTreeObserver().addOnGlobalLayoutListener(listener);
return binding.getRoot(); return binding.getRoot();
} }
@@ -1,6 +1,6 @@
package com.itsaky.androidide.handlers; package com.itsaky.androidide.handlers;
import com.itsaky.androidide.EditorActivity; import android.view.View;
import com.itsaky.androidide.R; import com.itsaky.androidide.R;
import com.itsaky.androidide.managers.PreferenceManager; import com.itsaky.androidide.managers.PreferenceManager;
import com.itsaky.androidide.models.AndroidProject; import com.itsaky.androidide.models.AndroidProject;
@@ -106,6 +106,7 @@ public class BuildServiceHandler extends IDEHandler implements IDEService.BuildL
activity().getApp().getPrefManager().putBoolean(PreferenceManager.KEY_IS_FIRST_PROJECT_BUILD, false); activity().getApp().getPrefManager().putBoolean(PreferenceManager.KEY_IS_FIRST_PROJECT_BUILD, false);
activity().invalidateOptionsMenu(); activity().invalidateOptionsMenu();
activity().getBinding().buildProgressIndicator.setVisibility(View.GONE);
} }
@Override @Override
@@ -117,6 +118,7 @@ public class BuildServiceHandler extends IDEHandler implements IDEService.BuildL
activity().getApp().getPrefManager().putBoolean(PreferenceManager.KEY_IS_FIRST_PROJECT_BUILD, false); activity().getApp().getPrefManager().putBoolean(PreferenceManager.KEY_IS_FIRST_PROJECT_BUILD, false);
activity().invalidateOptionsMenu(); activity().invalidateOptionsMenu();
activity().getBinding().buildProgressIndicator.setVisibility(View.GONE);
} }
@Override @Override
@@ -136,12 +138,13 @@ public class BuildServiceHandler extends IDEHandler implements IDEService.BuildL
} }
@Override @Override
public void prepare() { public void prepareBuild() {
boolean isFirstBuild = activity().getApp().getPrefManager().getBoolean(PreferenceManager.KEY_IS_FIRST_PROJECT_BUILD, true); boolean isFirstBuild = activity().getApp().getPrefManager().getBoolean(PreferenceManager.KEY_IS_FIRST_PROJECT_BUILD, true);
activity().setStatus(activity().getString(isFirstBuild ? R.string.preparing_first : R.string.preparing)); activity().setStatus(activity().getString(isFirstBuild ? R.string.preparing_first : R.string.preparing));
if(isFirstBuild) { if(isFirstBuild) {
activity().showFirstBuildNotice(); activity().showFirstBuildNotice();
} }
activity().getBinding().buildProgressIndicator.setVisibility(View.VISIBLE);
} }
private boolean isClasspathValid(String path) { private boolean isClasspathValid(String path) {
@@ -3,6 +3,7 @@ package com.itsaky.androidide.language.groovy;
import com.itsaky.androidide.syntax.lexer.impls.groovy.GroovyLexerImpl; import com.itsaky.androidide.syntax.lexer.impls.groovy.GroovyLexerImpl;
import com.itsaky.lsp.SemanticHighlight; import com.itsaky.lsp.SemanticHighlight;
import com.itsaky.lsp.services.IDELanguageServer; import com.itsaky.lsp.services.IDELanguageServer;
import io.github.rosemoe.editor.interfaces.EditorLanguage;
import io.github.rosemoe.editor.text.Content; import io.github.rosemoe.editor.text.Content;
import io.github.rosemoe.editor.text.TextAnalyzeResult; import io.github.rosemoe.editor.text.TextAnalyzeResult;
import io.github.rosemoe.editor.text.TextAnalyzer; import io.github.rosemoe.editor.text.TextAnalyzer;
@@ -11,11 +12,17 @@ import java.util.Map;
import org.eclipse.lsp4j.Diagnostic; import org.eclipse.lsp4j.Diagnostic;
public class GroovyAnalyzer extends io.github.rosemoe.editor.langs.AbstractCodeAnalyzer { public class GroovyAnalyzer extends io.github.rosemoe.editor.langs.AbstractCodeAnalyzer {
private final EditorLanguage language;
public GroovyAnalyzer (EditorLanguage language) {
this.language = language;
}
@Override @Override
public void analyze(IDELanguageServer server, File file, CharSequence content, TextAnalyzeResult colors, TextAnalyzer.AnalyzeThread.Delegate delegate) { public void analyze(IDELanguageServer server, File file, CharSequence content, TextAnalyzeResult colors, TextAnalyzer.AnalyzeThread.Delegate delegate) {
try { try {
GroovyLexerImpl lexer = new GroovyLexerImpl((Content) content, colors); GroovyLexerImpl lexer = new GroovyLexerImpl(this.language, (Content) content, colors);
lexer.init(); lexer.init();
// Adding spans, hex colors, block lines and all is handled by JavaLexerImpl // Adding spans, hex colors, block lines and all is handled by JavaLexerImpl
@@ -8,6 +8,7 @@ import com.itsaky.lsp.services.IDELanguageServer;
import io.github.rosemoe.editor.interfaces.AutoCompleteProvider; import io.github.rosemoe.editor.interfaces.AutoCompleteProvider;
import io.github.rosemoe.editor.interfaces.CodeAnalyzer; import io.github.rosemoe.editor.interfaces.CodeAnalyzer;
import io.github.rosemoe.editor.interfaces.NewlineHandler; import io.github.rosemoe.editor.interfaces.NewlineHandler;
import io.github.rosemoe.editor.text.CharPosition;
import io.github.rosemoe.editor.text.TextUtils; import io.github.rosemoe.editor.text.TextUtils;
import io.github.rosemoe.editor.widget.SymbolPairMatch; import io.github.rosemoe.editor.widget.SymbolPairMatch;
import java.io.File; import java.io.File;
@@ -26,7 +27,7 @@ public class GroovyLanguage extends BaseLanguage {
public GroovyLanguage(File file) { public GroovyLanguage(File file) {
super(file); super(file);
analyzer = new GroovyAnalyzer(); analyzer = new GroovyAnalyzer(this);
completor = new GroovyAutoComplete(); completor = new GroovyAutoComplete();
} }
@@ -107,7 +108,7 @@ public class GroovyLanguage extends BaseLanguage {
class BraceHandler implements NewlineHandler { class BraceHandler implements NewlineHandler {
@Override @Override
public boolean matchesRequirement(String beforeText, String afterText) { public boolean matchesRequirement(String beforeText, String afterText, CharPosition cursor) {
beforeText = beforeText.trim(); beforeText = beforeText.trim();
afterText = afterText.trim(); afterText = afterText.trim();
return beforeText.endsWith("{") && afterText.startsWith("}"); return beforeText.endsWith("{") && afterText.startsWith("}");
@@ -10,6 +10,7 @@ import com.itsaky.lsp.services.IDELanguageServer;
import io.github.rosemoe.editor.interfaces.AutoCompleteProvider; import io.github.rosemoe.editor.interfaces.AutoCompleteProvider;
import io.github.rosemoe.editor.interfaces.CodeAnalyzer; import io.github.rosemoe.editor.interfaces.CodeAnalyzer;
import io.github.rosemoe.editor.interfaces.NewlineHandler; import io.github.rosemoe.editor.interfaces.NewlineHandler;
import io.github.rosemoe.editor.text.CharPosition;
import io.github.rosemoe.editor.text.TextUtils; import io.github.rosemoe.editor.text.TextUtils;
import io.github.rosemoe.editor.widget.SymbolPairMatch; import io.github.rosemoe.editor.widget.SymbolPairMatch;
import java.io.File; import java.io.File;
@@ -22,14 +23,20 @@ public class JavaLanguage extends BaseLanguage {
private final JavaLexerImpl lexer; private final JavaLexerImpl lexer;
private final JavaAutoComplete complete; private final JavaAutoComplete complete;
private final NewlineHandler[] newlineHandlers;
public JavaLanguage() { public JavaLanguage() {
this(null); this(null);
} }
public JavaLanguage(File file) { public JavaLanguage(File file) {
super(file); super(file);
this.lexer = new JavaLexerImpl(); this.lexer = new JavaLexerImpl(this);
this.complete = new JavaAutoComplete(); this.complete = new JavaAutoComplete();
this.newlineHandlers = new NewlineHandler[2];
this.newlineHandlers[0] = new BraceHandler();
this.newlineHandlers[1] = this.lexer.stringHandler;
} }
@Override @Override
@@ -92,10 +99,8 @@ public class JavaLanguage extends BaseLanguage {
@Override @Override
public CharSequence format(CharSequence content) { public CharSequence format(CharSequence content) {
return content; return content;
} }
private NewlineHandler[] newlineHandlers = new NewlineHandler[] { new BraceHandler() };
@Override @Override
public NewlineHandler[] getNewlineHandlers() { public NewlineHandler[] getNewlineHandlers() {
return newlineHandlers; return newlineHandlers;
@@ -104,7 +109,7 @@ public class JavaLanguage extends BaseLanguage {
class BraceHandler implements NewlineHandler { class BraceHandler implements NewlineHandler {
@Override @Override
public boolean matchesRequirement(String beforeText, String afterText) { public boolean matchesRequirement(String beforeText, String afterText, CharPosition cursor) {
return beforeText.endsWith("{") && afterText.startsWith("}"); return beforeText.endsWith("{") && afterText.startsWith("}");
} }
@@ -32,6 +32,7 @@ import java.util.Optional;
import org.eclipse.lsp4j.DidChangeWatchedFilesParams; import org.eclipse.lsp4j.DidChangeWatchedFilesParams;
import org.eclipse.lsp4j.FileChangeType; import org.eclipse.lsp4j.FileChangeType;
import org.eclipse.lsp4j.FileEvent; import org.eclipse.lsp4j.FileEvent;
import com.blankj.utilcode.util.ThreadUtils;
public class IDEService implements ShellServer.Callback { public class IDEService implements ShellServer.Callback {
@@ -77,8 +78,8 @@ public class IDEService implements ShellServer.Callback {
this.isRunning = true; this.isRunning = true;
} }
public IDEService setListener(BuildListener listener) { public IDEService setListener(final BuildListener listener) {
this.listener = listener; this.listener = listener == null ? null : new MainThreadBuildListener(listener);
return this; return this;
} }
@@ -285,7 +286,7 @@ public class IDEService implements ShellServer.Callback {
shell.bgAppend(String.format("cd \"%s\"", new File(projectRoot, "app").getAbsolutePath())); shell.bgAppend(String.format("cd \"%s\"", new File(projectRoot, "app").getAbsolutePath()));
shell.bgAppend(getArguments(task.getTasks())); shell.bgAppend(getArguments(task.getTasks()));
isBuilding = true; isBuilding = true;
listener.prepare(); listener.prepareBuild();
} }
} }
@@ -385,6 +386,78 @@ public class IDEService implements ShellServer.Callback {
return isBuilding; return isBuilding;
} }
private class MainThreadBuildListener implements BuildListener {
private final BuildListener listener;
public MainThreadBuildListener(BuildListener listener) {
this.listener = listener;
}
@Override
public void onBuildModified() {
ThreadUtils.runOnUiThread(() -> {
listener.onBuildModified();
});
}
@Override
public void onProjectLoaded(IDEProject project, Optional<IDEModule> appModule) {
ThreadUtils.runOnUiThread(() -> {
listener.onProjectLoaded(project, appModule);
});
}
@Override
public void onStartingGradleDaemon(GradleTask task) {
ThreadUtils.runOnUiThread(() -> {
listener.onStartingGradleDaemon(task);
});
}
@Override
public void onRunTask(GradleTask task, String name) {
ThreadUtils.runOnUiThread(() -> {
listener.onRunTask(task, name);
});
}
@Override
public void onBuildSuccessful(GradleTask task, String msg) {
ThreadUtils.runOnUiThread(() -> {
listener.onBuildSuccessful(task, msg);
});
}
@Override
public void onBuildFailed(GradleTask task, String msg) {
ThreadUtils.runOnUiThread(() -> {
listener.onBuildFailed(task, msg);
});
}
@Override
public void saveFiles() {
ThreadUtils.runOnUiThread(() -> {
listener.saveFiles();
});
}
@Override
public void appendOutput(GradleTask task, CharSequence text) {
ThreadUtils.runOnUiThread(() -> {
listener.appendOutput(task, text);
});
}
@Override
public void prepareBuild() {
ThreadUtils.runOnUiThread(() -> {
listener.prepareBuild();
});
}
}
/** /**
* A client should implement this interface to get callbacks about a build * A client should implement this interface to get callbacks about a build
*/ */
@@ -449,7 +522,7 @@ public class IDEService implements ShellServer.Callback {
/** /**
* Called to notify the client to prepare for a build * Called to notify the client to prepare for a build
*/ */
void prepare(); void prepareBuild();
} }
/** /**
@@ -17,6 +17,7 @@ import java.util.Collections;
import java.util.List; import java.util.List;
import java.util.regex.Matcher; import java.util.regex.Matcher;
import java.util.regex.Pattern; import java.util.regex.Pattern;
import com.blankj.utilcode.util.ThreadUtils;
public class ShellServer extends Thread { public class ShellServer extends Thread {
@@ -5,18 +5,32 @@ import com.itsaky.androidide.syntax.lexer.Lexer;
import com.itsaky.androidide.syntax.lexer.impls.BaseJavaLexer; import com.itsaky.androidide.syntax.lexer.impls.BaseJavaLexer;
import com.itsaky.androidide.syntax.lexer.tokens.Token; import com.itsaky.androidide.syntax.lexer.tokens.Token;
import com.itsaky.androidide.syntax.lexer.tokens.TokenType; import com.itsaky.androidide.syntax.lexer.tokens.TokenType;
import com.itsaky.androidide.utils.LSPUtils;
import io.github.rosemoe.editor.interfaces.NewlineHandler;
import io.github.rosemoe.editor.struct.BlockLine; import io.github.rosemoe.editor.struct.BlockLine;
import io.github.rosemoe.editor.text.CharPosition;
import io.github.rosemoe.editor.text.Content; import io.github.rosemoe.editor.text.Content;
import io.github.rosemoe.editor.text.TextAnalyzeResult; import io.github.rosemoe.editor.text.TextAnalyzeResult;
import io.github.rosemoe.editor.text.TextUtils;
import io.github.rosemoe.editor.widget.EditorColorScheme; import io.github.rosemoe.editor.widget.EditorColorScheme;
import java.io.IOException; import java.io.IOException;
import java.io.StringReader; import java.io.StringReader;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.antlr.v4.runtime.CharStreams; import org.antlr.v4.runtime.CharStreams;
import org.eclipse.lsp4j.Range;
import io.github.rosemoe.editor.interfaces.EditorLanguage;
public class GroovyLexerImpl extends BaseJavaLexer implements Lexer { public class GroovyLexerImpl extends BaseJavaLexer implements Lexer {
public GroovyLexerImpl(Content content, TextAnalyzeResult colors) { private final EditorLanguage language;
private final Map<Integer, List<Range>> stringMap = new HashMap<>();
public final MultilineStringHandler stringHandler = new MultilineStringHandler();
public GroovyLexerImpl(EditorLanguage language, Content content, TextAnalyzeResult colors) {
this.language = language;
this.content = content; this.content = content;
this.colors = colors; this.colors = colors;
this.maxSwitch = 0; this.maxSwitch = 0;
@@ -283,4 +297,46 @@ public class GroovyLexerImpl extends BaseJavaLexer implements Lexer {
return type; return type;
} }
private class MultilineStringHandler implements NewlineHandler {
@Override
public boolean matchesRequirement(String beforeText, String afterText, CharPosition cursor) {
if(language == null || stringMap == null || stringMap.isEmpty()) {
return false;
}
final List<Range> ranges = stringMap.get(cursor.line);
if(ranges == null || ranges.isEmpty()) {
return false;
}
return isInRanges(ranges, cursor.line, cursor.column);
}
@Override
public NewlineHandler.HandleResult handleNewline(String beforeText, String afterText, int tabSize) {
int count = TextUtils.countLeadingSpaceCount(beforeText, tabSize);
int advance = language.getIndentAdvance(beforeText) + 1;
final StringBuilder sb = new StringBuilder("\\n\" + \n") // Appends: \n" + <new-line>
.append(TextUtils.createIndent(count + advance, tabSize, language.useTab()))
.append("\"");
return new HandleResult(sb, 0);
}
private boolean isInRanges (List<Range> ranges, int line, int column) {
if(ranges == null || ranges.isEmpty()) {
return false;
}
for (Range range : ranges) {
if (LSPUtils.isInRange(range, line, column)) {
return true;
}
}
return false;
}
}
} }
@@ -10,9 +10,8 @@ import com.itsaky.androidide.syntax.lexer.tokens.TokenType;
import com.itsaky.androidide.utils.LSPUtils; import com.itsaky.androidide.utils.LSPUtils;
import com.itsaky.androidide.utils.Logger; import com.itsaky.androidide.utils.Logger;
import com.itsaky.lsp.SemanticHighlight; import com.itsaky.lsp.SemanticHighlight;
import com.itsaky.lsp.SemanticHighlightsParams;
import com.itsaky.lsp.services.IDELanguageServer; import com.itsaky.lsp.services.IDELanguageServer;
import com.itsaky.lsp.services.IDETextDocumentService; import io.github.rosemoe.editor.interfaces.NewlineHandler;
import io.github.rosemoe.editor.struct.BlockLine; import io.github.rosemoe.editor.struct.BlockLine;
import io.github.rosemoe.editor.struct.Span; import io.github.rosemoe.editor.struct.Span;
import io.github.rosemoe.editor.text.CharPosition; import io.github.rosemoe.editor.text.CharPosition;
@@ -20,28 +19,34 @@ import io.github.rosemoe.editor.text.Content;
import io.github.rosemoe.editor.text.Indexer; import io.github.rosemoe.editor.text.Indexer;
import io.github.rosemoe.editor.text.TextAnalyzeResult; import io.github.rosemoe.editor.text.TextAnalyzeResult;
import io.github.rosemoe.editor.text.TextAnalyzer; import io.github.rosemoe.editor.text.TextAnalyzer;
import io.github.rosemoe.editor.text.TextUtils;
import io.github.rosemoe.editor.widget.EditorColorScheme; import io.github.rosemoe.editor.widget.EditorColorScheme;
import java.io.File; import java.io.File;
import java.io.IOException; import java.util.ArrayList;
import java.io.StringReader;
import java.util.Collections; import java.util.Collections;
import java.util.HashMap; import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Locale; import java.util.Locale;
import java.util.Map; import java.util.Map;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import org.antlr.v4.runtime.CharStreams; import org.antlr.v4.runtime.CharStreams;
import org.eclipse.lsp4j.Diagnostic; import org.eclipse.lsp4j.Diagnostic;
import org.eclipse.lsp4j.Position; import org.eclipse.lsp4j.Position;
import org.eclipse.lsp4j.Range; import org.eclipse.lsp4j.Range;
import org.eclipse.lsp4j.TextDocumentIdentifier; import io.github.rosemoe.editor.interfaces.EditorLanguage;
public class JavaLexerImpl extends io.github.rosemoe.editor.langs.AbstractCodeAnalyzer { public class JavaLexerImpl extends io.github.rosemoe.editor.langs.AbstractCodeAnalyzer {
private final EditorLanguage language;
private HighlightRangeHelper helper; private HighlightRangeHelper helper;
private Map<Integer, Map<Integer, Diagnostic>> diagnostics = new HashMap<>(); private Map<Integer, Map<Integer, Diagnostic>> diagnostics = new HashMap<>();
private final Map<Integer, List<Range>> stringMap = new HashMap<>();
public final MultilineStringHandler stringHandler = new MultilineStringHandler();
public JavaLexerImpl(EditorLanguage language) {
this.language = language;
}
@Override @Override
public void setSemanticHighlights(SemanticHighlight highlights) { public void setSemanticHighlights(SemanticHighlight highlights) {
@@ -59,6 +64,9 @@ public class JavaLexerImpl extends io.github.rosemoe.editor.langs.AbstractCodeAn
} catch (Throwable th) { } catch (Throwable th) {
return; return;
} }
stringMap.clear();
while (delegate.shouldAnalyze()) { while (delegate.shouldAnalyze()) {
// null = EOF // null = EOF
if(lexer.nextToken() == null) if(lexer.nextToken() == null)
@@ -120,6 +128,48 @@ public class JavaLexerImpl extends io.github.rosemoe.editor.langs.AbstractCodeAn
return diagnostics.get(line); return diagnostics.get(line);
} }
private class MultilineStringHandler implements NewlineHandler {
@Override
public boolean matchesRequirement(String beforeText, String afterText, CharPosition cursor) {
if(language == null || stringMap == null || stringMap.isEmpty()) {
return false;
}
final List<Range> ranges = stringMap.get(cursor.line);
if(ranges == null || ranges.isEmpty()) {
return false;
}
return isInRanges(ranges, cursor.line, cursor.column);
}
@Override
public NewlineHandler.HandleResult handleNewline(String beforeText, String afterText, int tabSize) {
int count = TextUtils.countLeadingSpaceCount(beforeText, tabSize);
int advance = language.getIndentAdvance(beforeText) + 1;
final StringBuilder sb = new StringBuilder("\\n\" + \n") // Appends: \n" + <new-line>
.append(TextUtils.createIndent(count + advance, tabSize, language.useTab()))
.append("\"");
return new HandleResult(sb, 0);
}
private boolean isInRanges (List<Range> ranges, int line, int column) {
if(ranges == null || ranges.isEmpty()) {
return false;
}
for (Range range : ranges) {
if (LSPUtils.isInRange(range, line, column)) {
return true;
}
}
return false;
}
}
public class JavaLexerAnalyzer extends BaseJavaLexer implements Lexer { public class JavaLexerAnalyzer extends BaseJavaLexer implements Lexer {
private final HighlightRangeHelper helper; private final HighlightRangeHelper helper;
@@ -250,7 +300,16 @@ public class JavaLexerImpl extends io.github.rosemoe.editor.langs.AbstractCodeAn
Position start = new Position(line, column); Position start = new Position(line, column);
Position end = new Position(line, column + currentToken.getText().length()); Position end = new Position(line, column + currentToken.getText().length());
colors.addStringRange(line, new Range(start, end)); colors.addStringRange(line, new Range(start, end));
{
List<Range> ranges = stringMap.get(line);
if(ranges == null) {
ranges = new ArrayList<>();
}
ranges.add(new Range(start, end));
stringMap.put(line, ranges);
}
addHexColorIfPresent(); addHexColorIfPresent();
break; break;
case JavaLexer.LPAREN : case JavaLexer.LPAREN :
@@ -14,6 +14,7 @@
* limitations under the License. * limitations under the License.
*/ */
package io.github.rosemoe.editor.interfaces; package io.github.rosemoe.editor.interfaces;
import io.github.rosemoe.editor.text.CharPosition;
/** /**
* Perform text processing when user enters '\n' and selection size is 0 * Perform text processing when user enters '\n' and selection size is 0
@@ -27,7 +28,7 @@ public interface NewlineHandler {
* @param afterText Text of line after cursor * @param afterText Text of line after cursor
* @return Whether this handler should be called * @return Whether this handler should be called
*/ */
boolean matchesRequirement(String beforeText, String afterText); boolean matchesRequirement(String beforeText, String afterText, CharPosition cursor);
/** /**
* Handle newline and return processed content to insert * Handle newline and return processed content to insert
@@ -4334,7 +4334,7 @@ public class CodeEditor extends View implements ContentListener, TextAnalyzer.Ca
boolean consumed = false; boolean consumed = false;
for (NewlineHandler handler : handlers) { for (NewlineHandler handler : handlers) {
if (handler != null) { if (handler != null) {
if (handler.matchesRequirement(beforeText, afterText)) { if (handler.matchesRequirement(beforeText, afterText, getCursor().left())) {
try { try {
NewlineHandler.HandleResult result = handler.handleNewline(beforeText, afterText, getTabWidth()); NewlineHandler.HandleResult result = handler.handleNewline(beforeText, afterText, getTabWidth());
if (result != null) { if (result != null) {
@@ -28,6 +28,14 @@
android:background="@color/primaryDarkColor" android:background="@color/primaryDarkColor"
android:id="@+id/editor_toolbar"/> android:id="@+id/editor_toolbar"/>
<com.google.android.material.progressindicator.LinearProgressIndicator
android:id="@+id/build_progress_indicator"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:indeterminate="true"
android:visibility="gone"
app:indicatorColor="@color/secondaryColor"/>
<com.itsaky.androidide.views.MaterialBanner <com.itsaky.androidide.views.MaterialBanner
android:id="@+id/syncBanner" android:id="@+id/syncBanner"
android:layout_height="wrap_content" android:layout_height="wrap_content"
@@ -5,6 +5,10 @@
<group <group
android:title="@string/group_project" android:title="@string/group_project"
android:id="@+id/editornav_group_project"> android:id="@+id/editornav_group_project">
<item
android:id="@+id/editornav_terminal"
android:icon="@drawable/ic_terminal"
android:title="@string/btn_terminal"/>
<item <item
android:id="@+id/editornav_close_project" android:id="@+id/editornav_close_project"
android:icon="@drawable/ic_close" android:icon="@drawable/ic_close"
Binary file not shown.
Vendored
+1 -1
View File
@@ -72,7 +72,7 @@ case "`uname`" in
Darwin* ) Darwin* )
darwin=true darwin=true
;; ;;
MINGW* ) MSYS* | MINGW* )
msys=true msys=true
;; ;;
NONSTOP* ) NONSTOP* )