Add preference for matching partial names in java completion

This commit is contained in:
Akash Yadav
2022-01-26 12:44:03 +05:30
parent a9373f7ab0
commit 7bd21eb6f9
19 changed files with 319 additions and 92 deletions
+5
View File
@@ -6,9 +6,14 @@
<entry key="..\:/Projects/AndroidStudioProjects/AndroidIDE/app/src/main/res/drawable-hdpi/ic_expand_selection.xml" value="0.20833333333333334" />
<entry key="..\:/Projects/AndroidStudioProjects/AndroidIDE/app/src/main/res/drawable/bg_design_container_background.xml" value="0.1" />
<entry key="..\:/Projects/AndroidStudioProjects/AndroidIDE/app/src/main/res/drawable/bg_ui_view_pressed.xml" value="0.1" />
<entry key="..\:/Projects/AndroidStudioProjects/AndroidIDE/app/src/main/res/drawable/ic_code.xml" value="0.19907407407407407" />
<entry key="..\:/Projects/AndroidStudioProjects/AndroidIDE/app/src/main/res/drawable/ic_code_actions.xml" value="0.19907407407407407" />
<entry key="..\:/Projects/AndroidStudioProjects/AndroidIDE/app/src/main/res/drawable/ic_completions.xml" value="0.19907407407407407" />
<entry key="..\:/Projects/AndroidStudioProjects/AndroidIDE/app/src/main/res/drawable/ic_github.xml" value="0.21837606837606838" />
<entry key="..\:/Projects/AndroidStudioProjects/AndroidIDE/app/src/main/res/drawable/ic_linear_layout.xml" value="0.175" />
<entry key="..\:/Projects/AndroidStudioProjects/AndroidIDE/app/src/main/res/drawable/ic_relative_layout.xml" value="0.175" />
<entry key="..\:/Projects/AndroidStudioProjects/AndroidIDE/app/src/main/res/drawable/ic_signature_help.xml" value="0.19907407407407407" />
<entry key="..\:/Projects/AndroidStudioProjects/AndroidIDE/app/src/main/res/drawable/ic_text_lower.xml" value="0.19907407407407407" />
<entry key="..\:/Projects/AndroidStudioProjects/AndroidIDE/app/src/main/res/layout/activity_about.xml" value="0.264" />
<entry key="..\:/Projects/AndroidStudioProjects/AndroidIDE/app/src/main/res/layout/activity_crash_handler.xml" value="0.25" />
<entry key="..\:/Projects/AndroidStudioProjects/AndroidIDE/app/src/main/res/layout/activity_designer.xml" value="0.264" />
Binary file not shown.
@@ -88,6 +88,7 @@ import com.itsaky.androidide.managers.PreferenceManager;
import com.itsaky.androidide.managers.ToolsManager;
import com.itsaky.androidide.models.DiagnosticGroup;
import com.itsaky.androidide.models.LogLine;
import com.itsaky.androidide.models.PrefBasedJavaServerSettings;
import com.itsaky.androidide.models.SaveResult;
import com.itsaky.androidide.models.SearchResult;
import com.itsaky.androidide.models.SheetOption;
@@ -1293,9 +1294,11 @@ public class EditorActivity extends StudioActivity implements FileTreeFragment.F
.getProjectPath ()
).toPath ()
);
final var params = new InitializeParams (workspaceRoots);
javaLanguageServer.connectClient (client);
javaLanguageServer.applySettings (PrefBasedJavaServerSettings.getInstance ());
javaLanguageServer.initialize (params);
}
@@ -92,7 +92,7 @@ public class BuildPreferences extends BasePreferenceFragment implements Preferen
"--warning-mode all"
};
final boolean[] checked = {
getPrefManager().isStracktraceEnabled(),
getPrefManager().isStackTraceEnabled (),
getPrefManager().isGradleInfoEnabled(),
getPrefManager().isGradleDebugEnabled(),
getPrefManager().isGradleScanEnabled(),
@@ -20,15 +20,18 @@ package com.itsaky.androidide.fragments.preferences;
import android.os.Bundle;
import android.view.LayoutInflater;
import androidx.preference.Preference;
import androidx.preference.PreferenceScreen;
import androidx.preference.PreferenceCategory;
import androidx.preference.SwitchPreference;
import com.google.android.material.dialog.MaterialAlertDialogBuilder;
import com.itsaky.androidide.R;
import com.itsaky.androidide.app.StudioApp;
import com.itsaky.androidide.databinding.LayoutTextSizeSliderBinding;
import com.itsaky.androidide.models.ConstantsBridge;
import com.itsaky.androidide.models.PrefBasedJavaServerSettings;
import com.itsaky.androidide.utils.DialogUtils;
import static com.itsaky.androidide.managers.PreferenceManager.*;
import static com.itsaky.androidide.models.PrefBasedJavaServerSettings.*;
public class EditorPreferences extends BasePreferenceFragment implements Preference.OnPreferenceChangeListener, Preference.OnPreferenceClickListener {
@@ -37,11 +40,19 @@ public class EditorPreferences extends BasePreferenceFragment implements Prefere
super.onCreatePreferences(p1, p2);
if(getContext() == null) return;
final PreferenceScreen screen = getPreferenceScreen();
final Preference fontSize = new Preference(getContext());
final Preference nonPrintable = new Preference(getContext());
final Preference tabSize = new Preference(getContext());
final SwitchPreference drawHex = new SwitchPreference(getContext());
final var screen = getPreferenceScreen();
final var commonCategory = new PreferenceCategory (getContext ());
final var javaCategory = new PreferenceCategory (getContext ());
final var fontSize = new Preference(getContext());
final var nonPrintable = new Preference(getContext());
final var tabSize = new Preference(getContext());
final var drawHex = new SwitchPreference(getContext());
final var javaMatchLower = new SwitchPreference (getContext ());
screen.addPreference (commonCategory);
screen.addPreference (javaCategory);
fontSize.setIcon(R.drawable.ic_text_size);
fontSize.setKey(KEY_EDITOR_FONT_SIZE);
@@ -62,34 +73,50 @@ public class EditorPreferences extends BasePreferenceFragment implements Prefere
drawHex.setKey(KEY_EDITOR_DRAW_HEX);
drawHex.setTitle(R.string.idepref_editor_drawhexcolors_title);
drawHex.setSummary(R.string.idepref_editor_drawhexcolors_summary);
screen.addPreference(fontSize);
screen.addPreference(nonPrintable);
screen.addPreference(tabSize);
screen.addPreference(drawHex);
javaMatchLower.setKey (KEY_JAVA_PREF_MATCH_LOWER);
javaMatchLower.setIcon (R.drawable.ic_text_lower);
javaMatchLower.setTitle (getString(R.string.idepref_java_matchLower_title));
javaMatchLower.setSummary (getString(R.string.idepref_java_matchLower_summary));
commonCategory.setTitle (getString(R.string.idepref_editor_category_common));
commonCategory.addPreference(fontSize);
commonCategory.addPreference(nonPrintable);
commonCategory.addPreference(tabSize);
commonCategory.addPreference(drawHex);
javaCategory.setTitle (getString(R.string.idepref_editor_category_java));
javaCategory.addPreference (javaMatchLower);
setPreferenceScreen(screen);
fontSize.setOnPreferenceClickListener(this);
nonPrintable.setOnPreferenceClickListener(this);
tabSize.setOnPreferenceClickListener(this);
drawHex.setOnPreferenceChangeListener(this);
javaMatchLower.setOnPreferenceChangeListener (this);
drawHex.setChecked(getPrefManager().getBoolean(KEY_EDITOR_DRAW_HEX, true));
javaMatchLower.setChecked (getPrefManager ().getBoolean (KEY_JAVA_PREF_MATCH_LOWER, false));
}
@Override
public boolean onPreferenceChange(Preference p1, Object p2) {
if(p1.getKey().equals(KEY_EDITOR_DRAW_HEX)) {
boolean drawHex = (Boolean) p2;
getPrefManager().putBoolean(KEY_EDITOR_DRAW_HEX, drawHex);
public boolean onPreferenceChange(Preference preference, Object newValue) {
final boolean value = (boolean) newValue;
if(preference.getKey().equals(KEY_EDITOR_DRAW_HEX)) {
getPrefManager().putBoolean(KEY_EDITOR_DRAW_HEX, value);
ConstantsBridge.EDITOR_PREF_DRAW_HEX_CHANGED = true;
} else if (preference.getKey ().equals (KEY_JAVA_PREF_MATCH_LOWER)) {
getPrefManager ().putBoolean (KEY_JAVA_PREF_MATCH_LOWER, value);
final var javaServer = StudioApp.getInstance ().getJavaLanguageServer ();
javaServer.applySettings (PrefBasedJavaServerSettings.getInstance ());
}
return true;
}
@Override
public boolean onPreferenceClick(Preference p1) {
final String key = p1.getKey();
public boolean onPreferenceClick(Preference preference) {
final String key = preference.getKey();
if(key.equals(KEY_EDITOR_FONT_SIZE)) {
showTextSizeDialog();
} else if(key.equals(KEY_EDITOR_PRINTABLE_CHARS)) {
@@ -115,7 +142,7 @@ public class EditorPreferences extends BasePreferenceFragment implements Prefere
builder.setTitle(R.string.title_tab_size);
builder.setSingleChoiceItems(sizes, current, (d, i) -> {
d.dismiss();
// Reversing the logic applied above...
int tabSize = (i + 1) * 2;
if(tabSize < 2 || tabSize > 8) tabSize = 4;
@@ -165,26 +192,26 @@ public class EditorPreferences extends BasePreferenceFragment implements Prefere
"Line breaks"
};
final boolean[] checked = {
getPrefManager().getBoolean(KEY_EDITORFLAG_WS_LEADING, true),
getPrefManager().getBoolean(KEY_EDITORFLAG_WS_TRAILING, false),
getPrefManager().getBoolean(KEY_EDITORFLAG_WS_INNER, true),
getPrefManager().getBoolean(KEY_EDITORFLAG_WS_EMPTY_LINE, true),
getPrefManager().getBoolean(KEY_EDITORFLAG_LINE_BREAK, true)
getPrefManager().getBoolean(KEY_EDITOR_FLAG_WS_LEADING, true),
getPrefManager().getBoolean(KEY_EDITOR_FLAG_WS_TRAILING, false),
getPrefManager().getBoolean(KEY_EDITOR_FLAG_WS_INNER, true),
getPrefManager().getBoolean(KEY_EDITOR_FLAG_WS_EMPTY_LINE, true),
getPrefManager().getBoolean(KEY_EDITOR_FLAG_LINE_BREAK, true)
};
final MaterialAlertDialogBuilder builder = DialogUtils.newMaterialDialogBuilder (getContext ());
builder.setTitle(R.string.idepref_editor_paintingflags_title);
builder.setMultiChoiceItems(labels, checked, (dialog, which, isChecked) -> {
if(which == 0) {
getPrefManager().putBoolean(KEY_EDITORFLAG_WS_LEADING, isChecked);
getPrefManager().putBoolean(KEY_EDITOR_FLAG_WS_LEADING, isChecked);
} else if(which == 1) {
getPrefManager().putBoolean(KEY_EDITORFLAG_WS_TRAILING, isChecked);
getPrefManager().putBoolean(KEY_EDITOR_FLAG_WS_TRAILING, isChecked);
} else if(which == 2) {
getPrefManager().putBoolean(KEY_EDITORFLAG_WS_INNER, isChecked);
getPrefManager().putBoolean(KEY_EDITOR_FLAG_WS_INNER, isChecked);
} else if(which == 3) {
getPrefManager().putBoolean(KEY_EDITORFLAG_WS_EMPTY_LINE, isChecked);
getPrefManager().putBoolean(KEY_EDITOR_FLAG_WS_EMPTY_LINE, isChecked);
} else if(which == 4) {
getPrefManager().putBoolean(KEY_EDITORFLAG_LINE_BREAK, isChecked);
getPrefManager().putBoolean(KEY_EDITOR_FLAG_LINE_BREAK, isChecked);
}
ConstantsBridge.EDITOR_PREF_FLAGS_CHANGED = true;
@@ -193,4 +220,4 @@ public class EditorPreferences extends BasePreferenceFragment implements Prefere
builder.setCancelable(false);
builder.show();
}
}
}
@@ -0,0 +1,55 @@
/*
* This file is part of AndroidIDE.
*
* AndroidIDE is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* AndroidIDE is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with AndroidIDE. If not, see <https://www.gnu.org/licenses/>.
*/
package com.itsaky.androidide.models;
import androidx.annotation.NonNull;
import com.itsaky.androidide.app.StudioApp;
import com.itsaky.androidide.managers.PreferenceManager;
import com.itsaky.lsp.java.models.DefaultJavaServerSettings;
/**
* Server settings for the java language server.
* @author Akash Yadav
*/
public class PrefBasedJavaServerSettings extends DefaultJavaServerSettings {
public static final String KEY_JAVA_PREF_MATCH_LOWER = "idepref_editor_java_matchLower";
private static PrefBasedJavaServerSettings instance;
private final PreferenceManager prefs;
public PrefBasedJavaServerSettings () {
this.prefs = StudioApp.getInstance ().getPrefManager ();
}
@NonNull
public static PrefBasedJavaServerSettings getInstance () {
if (instance == null) {
instance = new PrefBasedJavaServerSettings ();
}
return instance;
}
@Override
public boolean shouldMatchAllLowerCase () {
return prefs.getBoolean (KEY_JAVA_PREF_MATCH_LOWER, false);
}
}
@@ -241,7 +241,7 @@ public class IDEService {
args.add("--init-script");
args.add(Environment.INIT_SCRIPT.getAbsolutePath());
if (prefs.isStracktraceEnabled()) {
if (prefs.isStackTraceEnabled ()) {
args.add("--stacktrace");
}
if (prefs.isGradleInfoEnabled()) {
@@ -19,7 +19,6 @@ package com.itsaky.androidide.views;
import android.annotation.SuppressLint;
import android.content.Context;
import android.view.LayoutInflater;
import android.view.ViewTreeObserver;
import android.widget.FrameLayout;
import androidx.annotation.NonNull;
@@ -291,23 +290,23 @@ public class CodeEditorView extends FrameLayout {
if (flagsChanged) {
int flags = 0;
if (prefs.getBoolean (PreferenceManager.KEY_EDITORFLAG_WS_LEADING, true)) {
if (prefs.getBoolean (PreferenceManager.KEY_EDITOR_FLAG_WS_LEADING, true)) {
flags |= CodeEditor.FLAG_DRAW_WHITESPACE_LEADING;
}
if (prefs.getBoolean (PreferenceManager.KEY_EDITORFLAG_WS_TRAILING, false)) {
if (prefs.getBoolean (PreferenceManager.KEY_EDITOR_FLAG_WS_TRAILING, false)) {
flags |= CodeEditor.FLAG_DRAW_WHITESPACE_TRAILING;
}
if (prefs.getBoolean (PreferenceManager.KEY_EDITORFLAG_WS_INNER, true)) {
if (prefs.getBoolean (PreferenceManager.KEY_EDITOR_FLAG_WS_INNER, true)) {
flags |= CodeEditor.FLAG_DRAW_WHITESPACE_INNER;
}
if (prefs.getBoolean (PreferenceManager.KEY_EDITORFLAG_WS_EMPTY_LINE, true)) {
if (prefs.getBoolean (PreferenceManager.KEY_EDITOR_FLAG_WS_EMPTY_LINE, true)) {
flags |= CodeEditor.FLAG_DRAW_WHITESPACE_FOR_EMPTY_LINE;
}
if (prefs.getBoolean (PreferenceManager.KEY_EDITORFLAG_LINE_BREAK, true)) {
if (prefs.getBoolean (PreferenceManager.KEY_EDITOR_FLAG_LINE_BREAK, true)) {
flags |= CodeEditor.FLAG_DRAW_LINE_SEPARATOR;
}
@@ -0,0 +1,8 @@
<!-- drawable/format_letter_case_lower.xml -->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:height="24dp"
android:width="24dp"
android:viewportWidth="24"
android:viewportHeight="24">
<path android:fillColor="#ffffff" android:pathData="M20.06,18C20,17.83 19.91,17.54 19.86,17.11C19.19,17.81 18.38,18.16 17.45,18.16C16.62,18.16 15.93,17.92 15.4,17.45C14.87,17 14.6,16.39 14.6,15.66C14.6,14.78 14.93,14.1 15.6,13.61C16.27,13.12 17.21,12.88 18.43,12.88H19.83V12.24C19.83,11.75 19.68,11.36 19.38,11.07C19.08,10.78 18.63,10.64 18.05,10.64C17.53,10.64 17.1,10.76 16.75,11C16.4,11.25 16.23,11.54 16.23,11.89H14.77C14.77,11.46 14.92,11.05 15.22,10.65C15.5,10.25 15.93,9.94 16.44,9.71C16.95,9.5 17.5,9.36 18.13,9.36C19.11,9.36 19.87,9.6 20.42,10.09C20.97,10.58 21.26,11.25 21.28,12.11V16C21.28,16.8 21.38,17.42 21.58,17.88V18H20.06M17.66,16.88C18.11,16.88 18.54,16.77 18.95,16.56C19.35,16.35 19.65,16.07 19.83,15.73V14.16H18.7C16.93,14.16 16.04,14.63 16.04,15.57C16.04,16 16.19,16.3 16.5,16.53C16.8,16.76 17.18,16.88 17.66,16.88M5.46,13.71H9.53L7.5,8.29L5.46,13.71M6.64,6H8.36L13.07,18H11.14L10.17,15.43H4.82L3.86,18H1.93L6.64,6M22,20V22H14.5V20H22Z" />
</vector>
+5 -1
View File
@@ -355,5 +355,9 @@
<string name="msg_compiler_module_install_failed">Compiler module installation failed. The error was:\n%s</string>
<string name="msg_compiler_module_installed">Compiler module installed successfully!</string>
<string name="action_expand_selection">Expand selection</string>
<string name="idepref_java_matchLower_title">Match completions in lower case</string>
<string name="idepref_java_matchLower_summary">If enabled, then typing a lower case or upper case letters will suggest class names as well as scope members.</string>
<string name="idepref_editor_category_common">Common</string>
<string name="idepref_editor_category_java">Java</string>
</resources>
@@ -23,10 +23,8 @@ import android.content.SharedPreferences;
public class PreferenceManager {
private SharedPreferences prefs;
private final SharedPreferences prefs;
public static final int LOGSENDER_LATEST_VERSION = 102;
public static final String KEY_FRAMEWORK_DOWNLOADED = "framework_downloaded";
public static final String KEY_FRAMEWORK_INSTALLED = "framework_installed";
public static final String KEY_IS_FIRST_PROJECT_BUILD = "project_isFirstBuild";
@@ -35,26 +33,22 @@ public class PreferenceManager {
public static final String KEY_CONFIRM_PROJECT_OPEN = "idepref_general_confirmProjectOpen";
public static final String KEY_TERMINAL_USE_SYSTEM_SHELL = "idepref_general_terminalShell";
public static final String KEY_EDITORFLAG_WS_LEADING = "idepref_editor_wsLeading";
public static final String KEY_EDITORFLAG_WS_TRAILING = "idepref_editor_wsTrailing";
public static final String KEY_EDITORFLAG_WS_INNER = "idepref_editor_wsInner";
public static final String KEY_EDITORFLAG_WS_EMPTY_LINE = "idepref_editor_wsEmptyLine";
public static final String KEY_EDITORFLAG_LINE_BREAK = "idepref_editor_lineBreak";
public static final String KEY_EDITOR_FLAG_WS_LEADING = "idepref_editor_wsLeading";
public static final String KEY_EDITOR_FLAG_WS_TRAILING = "idepref_editor_wsTrailing";
public static final String KEY_EDITOR_FLAG_WS_INNER = "idepref_editor_wsInner";
public static final String KEY_EDITOR_FLAG_WS_EMPTY_LINE = "idepref_editor_wsEmptyLine";
public static final String KEY_EDITOR_FLAG_LINE_BREAK = "idepref_editor_lineBreak";
public static final String KEY_EDITOR_DRAW_HEX = "idepref_editor_drawHexColors";
public static final String KEY_EDITOR_FONT_SIZE = "idepref_editor_fontSize";
public static final String KEY_EDITOR_PRINTABLE_CHARS = "idepref_editor_nonPrintableFlags";
public static final String KEY_EDITOR_TAB_SIZE = "idepref_editor_tabSize";
public static final String KEY_GRADLE_CURRENT_DIR = "idepref_customGradle_currentFolder";
public static final String KEY_GRADLE_FILENAMES = "idepref_customGradle_folderNames";
public static final String KEY_GRADLECMD_STACKTRACRE = "idepref_gradleCmd_stacktrace";
public static final String KEY_GRADLECMD_DEBUG = "idepref_gradleCmd_debug";
public static final String KEY_GRADLECMD_SCAN = "idepref_gradleCmd_scan";
public static final String KEY_GRADLECMD_INFO = "idepref_gradleCmd_info";
public static final String KEY_GRADLECMD_WARNINGMODE = "idepref_gradleCmd_warningMode";
public static final String KEY_LOGSENDER_CURRENT_VERSION = "logsender_currentVersion";
public static final String KEY_GRADLE_CMD_STACK_TRACE = "idepref_gradleCmd_stacktrace";
public static final String KEY_GRADLE_CMD_DEBUG = "idepref_gradleCmd_debug";
public static final String KEY_GRADLE_CMD_SCAN = "idepref_gradleCmd_scan";
public static final String KEY_GRADLE_CMD_INFO = "idepref_gradleCmd_info";
public static final String KEY_GRADLE_CMD_WARNING_MODE = "idepref_gradleCmd_warningMode";
public static final String KEY_LAST_OPENED_PROJECT = "ide_last_project";
public static final String NO_OPENED_PROJECT = "<NO_OPENED_PROJECT>";
@@ -135,44 +129,44 @@ public class PreferenceManager {
return isFrameworkDownloaded() && getBoolean(KEY_FRAMEWORK_INSTALLED);
}
public boolean isStracktraceEnabled() {
return getBoolean(KEY_GRADLECMD_STACKTRACRE);
public boolean isStackTraceEnabled () {
return getBoolean(KEY_GRADLE_CMD_STACK_TRACE);
}
public boolean isGradleInfoEnabled() {
return getBoolean(KEY_GRADLECMD_INFO, true);
return getBoolean(KEY_GRADLE_CMD_INFO, true);
}
public boolean isGradleDebugEnabled() {
return getBoolean(KEY_GRADLECMD_DEBUG);
return getBoolean(KEY_GRADLE_CMD_DEBUG);
}
public boolean isGradleScanEnabled() {
return getBoolean(KEY_GRADLECMD_SCAN);
return getBoolean(KEY_GRADLE_CMD_SCAN);
}
public boolean isGradleWarningEnabled() {
return getBoolean(KEY_GRADLECMD_WARNINGMODE);
return getBoolean(KEY_GRADLE_CMD_WARNING_MODE);
}
public PreferenceManager setGradleStacktraceEnabled(boolean enabled) {
return putBoolean(KEY_GRADLECMD_STACKTRACRE, enabled);
return putBoolean(KEY_GRADLE_CMD_STACK_TRACE, enabled);
}
public PreferenceManager setGradleInfoEnabled(boolean enabled) {
return putBoolean(KEY_GRADLECMD_INFO, enabled);
return putBoolean(KEY_GRADLE_CMD_INFO, enabled);
}
public PreferenceManager setGradleDebugEnabled(boolean enabled) {
return putBoolean(KEY_GRADLECMD_DEBUG, enabled);
return putBoolean(KEY_GRADLE_CMD_DEBUG, enabled);
}
public PreferenceManager setGradleScanEnabled(boolean enabled) {
return putBoolean(KEY_GRADLECMD_SCAN, enabled);
return putBoolean(KEY_GRADLE_CMD_SCAN, enabled);
}
public PreferenceManager setGradleWarningEnabled(boolean enabled) {
return putBoolean(KEY_GRADLECMD_WARNINGMODE, enabled);
return putBoolean(KEY_GRADLE_CMD_WARNING_MODE, enabled);
}
public int getEditorTabSize() {
@@ -0,0 +1,45 @@
/*
* This file is part of AndroidIDE.
*
* AndroidIDE is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* AndroidIDE is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with AndroidIDE. If not, see <https://www.gnu.org/licenses/>.
*/
package com.itsaky.lsp.api;
import com.itsaky.lsp.util.DefaultServerSettings;
/**
* @author Akash Yadav
*/
public class AbstractServiceProvider implements ConfigurableServiceProvider {
private IServerSettings settings;
public AbstractServiceProvider () {
this.settings = new DefaultServerSettings ();
}
@Override
public void applySettings (IServerSettings settings) {
if (settings == null) {
settings = new DefaultServerSettings ();
}
this.settings = settings;
}
public IServerSettings getSettings () {
return settings;
}
}
@@ -0,0 +1,35 @@
/*
* This file is part of AndroidIDE.
*
* AndroidIDE is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* AndroidIDE is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with AndroidIDE. If not, see <https://www.gnu.org/licenses/>.
*/
package com.itsaky.lsp.api;
import androidx.annotation.NonNull;
/**
* Base class for service providers which can be configured using
* {@link IServerSettings}.
*
* @author Akash Yadav
*/
public interface ConfigurableServiceProvider {
/**
* Apply the given settings to this service provider.
* @param settings The settings to apply. If {@code null}, {@link com.itsaky.lsp.util.DefaultServerSettings} should be used.
*/
void applySettings (IServerSettings settings);
}
@@ -73,4 +73,12 @@ public interface IServerSettings {
* @return {@code true} if enabled, {@code false} otherwise.
*/
boolean codeAnalysisEnabled ();
/**
* Called by the completions provider to check if
* it should match partial names in all lowercase.
*
* @return {@code true} if enabled, {@code false} otherwise.
*/
boolean shouldMatchAllLowerCase ();
}
@@ -24,7 +24,7 @@ import com.itsaky.lsp.api.IServerSettings
*
* @author Akash Yadav
*/
class DefaultServerSettings : IServerSettings {
open class DefaultServerSettings : IServerSettings {
override fun completionsEnabled(): Boolean = true
override fun codeActionsEnabled(): Boolean = true
override fun smartSelectionsEnabled(): Boolean = true
@@ -32,4 +32,6 @@ class DefaultServerSettings : IServerSettings {
override fun referencesEnabled(): Boolean = true
override fun definitionsEnabled(): Boolean = true
override fun codeAnalysisEnabled(): Boolean = true
override fun shouldMatchAllLowerCase(): Boolean = false
}
@@ -178,7 +178,7 @@ public class JavaLanguageServer implements ILanguageServer, IDocumentHandler {
return new NoCompletionsProvider ();
}
return new CompletionProvider (getCompiler ());
return new CompletionProvider (getCompiler (), this.settings);
}
@NonNull
@@ -0,0 +1,27 @@
/*
* This file is part of AndroidIDE.
*
* AndroidIDE is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* AndroidIDE is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with AndroidIDE. If not, see <https://www.gnu.org/licenses/>.
*/
package com.itsaky.lsp.java.models;
import com.itsaky.lsp.util.DefaultServerSettings;
/**
* Default settings for the java language server.
* @author Akash Yadav
*/
public class DefaultJavaServerSettings extends DefaultServerSettings {
}
@@ -23,7 +23,9 @@ import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import com.itsaky.androidide.utils.Logger;
import com.itsaky.lsp.api.AbstractServiceProvider;
import com.itsaky.lsp.api.ICompletionProvider;
import com.itsaky.lsp.api.IServerSettings;
import com.itsaky.lsp.java.compiler.CompileTask;
import com.itsaky.lsp.java.compiler.CompilerProvider;
import com.itsaky.lsp.java.FileStore;
@@ -92,7 +94,7 @@ import javax.lang.model.type.TypeMirror;
import javax.lang.model.type.TypeVariable;
import javax.lang.model.util.Types;
public class CompletionProvider implements ICompletionProvider {
public class CompletionProvider extends AbstractServiceProvider implements ICompletionProvider {
private final CompilerProvider compiler;
@@ -102,7 +104,10 @@ public class CompletionProvider implements ICompletionProvider {
private Path completingFile;
private long cursor;
public CompletionProvider (CompilerProvider compiler) {
public CompletionProvider (CompilerProvider compiler, IServerSettings settings) {
super ();
applySettings (settings);
this.compiler = compiler;
}
@@ -239,8 +244,11 @@ public class CompletionProvider implements ICompletionProvider {
CompletionResult list = new CompletionResult();
list.setItems (completeUsingScope (task, path, partial, endsWithParen));
addStaticImports(task, path.getCompilationUnit(), partial, endsWithParen, list);
if (!list.isIncomplete () && partial.length() > 0 && Character.isUpperCase(partial.charAt(0))) {
addClassNames(path.getCompilationUnit(), partial, list);
if (!list.isIncomplete ()) {
final boolean allLower = getSettings ().shouldMatchAllLowerCase ();
if (allLower || (partial.length () > 0 && Character.isUpperCase (partial.charAt (0)))) {
addClassNames(path.getCompilationUnit(), partial, list, allLower);
}
}
addKeywords(path, partial, list);
return list;
@@ -257,7 +265,7 @@ public class CompletionProvider implements ICompletionProvider {
keywords = METHOD_BODY_KEYWORDS;
}
for (String k : keywords) {
if (StringSearch.matchesPartialName(k, partial)) {
if (StringSearch.matchesPartialName(k, partial, getSettings ().shouldMatchAllLowerCase ())) {
list.getItems ().add(keyword(k));
}
}
@@ -281,7 +289,7 @@ public class CompletionProvider implements ICompletionProvider {
Trees trees = Trees.instance(task.task);
List<CompletionItem> list = new ArrayList<> ();
Scope scope = trees.getScope(path);
Predicate<CharSequence> filter = name -> StringSearch.matchesPartialName(name, partial);
Predicate<CharSequence> filter = name -> StringSearch.matchesPartialName(name, partial, true);
for (Element member : ScopeHelper.scopeMembers(task, scope, filter)) {
if (member.getKind() == ElementKind.METHOD) {
ExecutableElement method = (ExecutableElement) member;
@@ -311,7 +319,7 @@ public class CompletionProvider implements ICompletionProvider {
for (Element member : type.getEnclosedElements()) {
if (!member.getModifiers().contains(Modifier.STATIC)) continue;
if (!memberMatchesImport(id.getIdentifier(), member)) continue;
if (!StringSearch.matchesPartialName(member.getSimpleName(), partial)) continue;
if (!StringSearch.matchesPartialName(member.getSimpleName(), partial, getSettings ().shouldMatchAllLowerCase ())) continue;
if (member.getKind() == ElementKind.METHOD) {
putMethod((ExecutableElement) member, methods);
} else {
@@ -330,14 +338,14 @@ public class CompletionProvider implements ICompletionProvider {
}
private boolean importMatchesPartial(@NonNull Name staticImport, String partial) {
return staticImport.contentEquals("*") || StringSearch.matchesPartialName(staticImport, partial);
return staticImport.contentEquals("*") || StringSearch.matchesPartialName(staticImport, partial, getSettings ().shouldMatchAllLowerCase ());
}
private boolean memberMatchesImport(@NonNull Name staticImport, Element member) {
return staticImport.contentEquals("*") || staticImport.contentEquals(member.getSimpleName());
}
private void addClassNames(@NonNull CompilationUnitTree root, String partial, @NonNull CompletionResult list) {
private void addClassNames(@NonNull CompilationUnitTree root, String partial, @NonNull CompletionResult list, boolean allLower) {
String packageName = Objects.toString(root.getPackageName(), "");
Set<String> uniques = new HashSet<> ();
int previousSize = list.getItems ().size();
@@ -349,13 +357,13 @@ public class CompletionProvider implements ICompletionProvider {
.collect (Collectors.toSet ());
for (String className : compiler.packagePrivateTopLevelTypes(packageName)) {
if (!StringSearch.matchesPartialName(className, partial)) continue;
if (!StringSearch.matchesPartialName(className, partial, allLower)) continue;
list.getItems ().add(classItem(imports, file, className));
uniques.add(className);
}
for (String className : compiler.publicTopLevelTypes()) {
if (!StringSearch.matchesPartialName(simpleName(className), partial)) continue;
if (!StringSearch.matchesPartialName(simpleName(className), partial, allLower)) continue;
if (uniques.contains(className)) continue;
if (list.getItems ().size() > MAX_COMPLETION_ITEMS) {
list.setIncomplete (true);
@@ -371,14 +379,15 @@ public class CompletionProvider implements ICompletionProvider {
}
final ClassTree c = (ClassTree) t;
if (c.getModifiers ().getFlags ().isEmpty ()) {
// This is a package private class defined in the same file
final String name = packageName + "." + c.getSimpleName ();
list.getItems ().add (classItem (name));
if (list.getItems ().size () > MAX_COMPLETION_ITEMS) {
list.setIncomplete (true);
break;
}
if (!StringSearch.matchesPartialName (c.getSimpleName () == null ? "" : c.getSimpleName (), partial, allLower)) {
continue;
}
final String name = packageName + "." + c.getSimpleName ();
list.getItems ().add (classItem (name));
if (list.getItems ().size () > MAX_COMPLETION_ITEMS) {
list.setIncomplete (true);
break;
}
}
@@ -437,7 +446,7 @@ public class CompletionProvider implements ICompletionProvider {
Map<String, List<ExecutableElement>> methods = new HashMap<> ();
for (Element member : task.task.getElements().getAllMembers(typeElement)) {
if (member.getKind() == ElementKind.CONSTRUCTOR) continue;
if (!StringSearch.matchesPartialName(member.getSimpleName(), partial)) continue;
if (!StringSearch.matchesPartialName(member.getSimpleName(), partial, getSettings ().shouldMatchAllLowerCase ())) continue;
if (!trees.isAccessible(scope, member, type)) continue;
if (isStatic != member.getModifiers().contains(Modifier.STATIC)) continue;
if (member.getKind() == ElementKind.METHOD) {
@@ -530,7 +539,7 @@ public class CompletionProvider implements ICompletionProvider {
List<CompletionItem> list = new ArrayList<> ();
Map<String, List<ExecutableElement>> methods = new HashMap<> ();
for (Element member : task.task.getElements().getAllMembers(typeElement)) {
if (!StringSearch.matchesPartialName(member.getSimpleName(), partial)) continue;
if (!StringSearch.matchesPartialName(member.getSimpleName(), partial, getSettings ().shouldMatchAllLowerCase ())) continue;
if (member.getKind() != ElementKind.METHOD) continue;
if (!trees.isAccessible(scope, member, type)) continue;
if (!isStatic && member.getModifiers().contains(Modifier.STATIC)) continue;
@@ -587,7 +596,7 @@ public class CompletionProvider implements ICompletionProvider {
List<CompletionItem> list = new ArrayList<> ();
for (Element member : task.task.getElements().getAllMembers(element)) {
if (member.getKind() != ElementKind.ENUM_CONSTANT) continue;
if (!StringSearch.matchesPartialName(member.getSimpleName(), partial)) continue;
if (!StringSearch.matchesPartialName(member.getSimpleName(), partial, getSettings ().shouldMatchAllLowerCase ())) continue;
list.add(item(task, member));
}
@@ -29,6 +29,7 @@ import java.nio.charset.StandardCharsets;
import java.nio.file.NoSuchFileException;
import java.nio.file.Path;
import java.util.Arrays;
import java.util.Locale;
import java.util.Objects;
import java.util.logging.Logger;
import java.util.regex.Matcher;
@@ -444,9 +445,14 @@ public class StringSearch {
}
public static boolean matchesPartialName (CharSequence candidate, CharSequence partialName) {
return matchesPartialName (candidate, partialName, false);
}
public static boolean matchesPartialName (CharSequence candidate, CharSequence partialName, boolean allLower) {
if (candidate.length () < partialName.length ()) {
return false;
}
for (int i = 0; i < partialName.length (); i++) {
char char1 = candidate.charAt (i);
char char2 = partialName.charAt (i);
@@ -455,7 +461,7 @@ public class StringSearch {
// The make all the characters lower case
// So if the first character is upper case, we could assume that the user is expecting a class name
// Otherwise a variable name
if (i != 0) {
if (allLower || i != 0) {
char1 = Character.toLowerCase (char1);
char2 = Character.toLowerCase (char2);
}