diff --git a/.idea/misc.xml b/.idea/misc.xml
index 28e84c20f..c7b0a3074 100755
--- a/.idea/misc.xml
+++ b/.idea/misc.xml
@@ -6,9 +6,14 @@
+
+
+
+
+
diff --git a/app/src/main/assets/data/common/gradle-plugin.zip b/app/src/main/assets/data/common/gradle-plugin.zip
index 4ed14ebc6..ed342832b 100644
Binary files a/app/src/main/assets/data/common/gradle-plugin.zip and b/app/src/main/assets/data/common/gradle-plugin.zip differ
diff --git a/app/src/main/java/com/itsaky/androidide/EditorActivity.java b/app/src/main/java/com/itsaky/androidide/EditorActivity.java
index a5bca5145..2674950d4 100755
--- a/app/src/main/java/com/itsaky/androidide/EditorActivity.java
+++ b/app/src/main/java/com/itsaky/androidide/EditorActivity.java
@@ -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);
}
diff --git a/app/src/main/java/com/itsaky/androidide/fragments/preferences/BuildPreferences.java b/app/src/main/java/com/itsaky/androidide/fragments/preferences/BuildPreferences.java
index 7b0d2dd8e..1870e8d67 100755
--- a/app/src/main/java/com/itsaky/androidide/fragments/preferences/BuildPreferences.java
+++ b/app/src/main/java/com/itsaky/androidide/fragments/preferences/BuildPreferences.java
@@ -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(),
diff --git a/app/src/main/java/com/itsaky/androidide/fragments/preferences/EditorPreferences.java b/app/src/main/java/com/itsaky/androidide/fragments/preferences/EditorPreferences.java
index 77b1e51ba..bbc4176ee 100755
--- a/app/src/main/java/com/itsaky/androidide/fragments/preferences/EditorPreferences.java
+++ b/app/src/main/java/com/itsaky/androidide/fragments/preferences/EditorPreferences.java
@@ -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();
}
-}
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/itsaky/androidide/models/PrefBasedJavaServerSettings.java b/app/src/main/java/com/itsaky/androidide/models/PrefBasedJavaServerSettings.java
new file mode 100644
index 000000000..1864d80f9
--- /dev/null
+++ b/app/src/main/java/com/itsaky/androidide/models/PrefBasedJavaServerSettings.java
@@ -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 .
+ */
+
+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);
+ }
+}
diff --git a/app/src/main/java/com/itsaky/androidide/services/builder/IDEService.java b/app/src/main/java/com/itsaky/androidide/services/builder/IDEService.java
index aac75b8c7..a81d7b783 100755
--- a/app/src/main/java/com/itsaky/androidide/services/builder/IDEService.java
+++ b/app/src/main/java/com/itsaky/androidide/services/builder/IDEService.java
@@ -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()) {
diff --git a/app/src/main/java/com/itsaky/androidide/views/CodeEditorView.java b/app/src/main/java/com/itsaky/androidide/views/CodeEditorView.java
index e788471e6..3f17f61e1 100644
--- a/app/src/main/java/com/itsaky/androidide/views/CodeEditorView.java
+++ b/app/src/main/java/com/itsaky/androidide/views/CodeEditorView.java
@@ -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;
}
diff --git a/app/src/main/res/drawable/ic_text_lower.xml b/app/src/main/res/drawable/ic_text_lower.xml
new file mode 100644
index 000000000..aec47d537
--- /dev/null
+++ b/app/src/main/res/drawable/ic_text_lower.xml
@@ -0,0 +1,8 @@
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
index 542c53ced..62daf1b8a 100755
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -355,5 +355,9 @@
Compiler module installation failed. The error was:\n%s
Compiler module installed successfully!
Expand selection
-
+ Match completions in lower case
+ If enabled, then typing a lower case or upper case letters will suggest class names as well as scope members.
+ Common
+ Java
+
diff --git a/common/src/main/java/com/itsaky/androidide/managers/PreferenceManager.java b/common/src/main/java/com/itsaky/androidide/managers/PreferenceManager.java
index 342b20814..de7b68703 100755
--- a/common/src/main/java/com/itsaky/androidide/managers/PreferenceManager.java
+++ b/common/src/main/java/com/itsaky/androidide/managers/PreferenceManager.java
@@ -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 = "";
@@ -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() {
diff --git a/lsp/api/src/main/java/com/itsaky/lsp/api/AbstractServiceProvider.java b/lsp/api/src/main/java/com/itsaky/lsp/api/AbstractServiceProvider.java
new file mode 100644
index 000000000..6a96b6f3d
--- /dev/null
+++ b/lsp/api/src/main/java/com/itsaky/lsp/api/AbstractServiceProvider.java
@@ -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 .
+ */
+
+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;
+ }
+}
diff --git a/lsp/api/src/main/java/com/itsaky/lsp/api/ConfigurableServiceProvider.java b/lsp/api/src/main/java/com/itsaky/lsp/api/ConfigurableServiceProvider.java
new file mode 100644
index 000000000..d29790e23
--- /dev/null
+++ b/lsp/api/src/main/java/com/itsaky/lsp/api/ConfigurableServiceProvider.java
@@ -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 .
+ */
+
+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);
+}
diff --git a/lsp/api/src/main/java/com/itsaky/lsp/api/IServerSettings.java b/lsp/api/src/main/java/com/itsaky/lsp/api/IServerSettings.java
index b0875cf46..0733ebfcd 100644
--- a/lsp/api/src/main/java/com/itsaky/lsp/api/IServerSettings.java
+++ b/lsp/api/src/main/java/com/itsaky/lsp/api/IServerSettings.java
@@ -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 ();
}
diff --git a/lsp/api/src/main/java/com/itsaky/lsp/util/DefaultServerSettings.kt b/lsp/api/src/main/java/com/itsaky/lsp/util/DefaultServerSettings.kt
index 872613a82..1cf8460ec 100644
--- a/lsp/api/src/main/java/com/itsaky/lsp/util/DefaultServerSettings.kt
+++ b/lsp/api/src/main/java/com/itsaky/lsp/util/DefaultServerSettings.kt
@@ -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
}
\ No newline at end of file
diff --git a/lsp/java/src/main/java/com/itsaky/lsp/java/JavaLanguageServer.java b/lsp/java/src/main/java/com/itsaky/lsp/java/JavaLanguageServer.java
index 3b0f7bb11..9f61964dc 100644
--- a/lsp/java/src/main/java/com/itsaky/lsp/java/JavaLanguageServer.java
+++ b/lsp/java/src/main/java/com/itsaky/lsp/java/JavaLanguageServer.java
@@ -178,7 +178,7 @@ public class JavaLanguageServer implements ILanguageServer, IDocumentHandler {
return new NoCompletionsProvider ();
}
- return new CompletionProvider (getCompiler ());
+ return new CompletionProvider (getCompiler (), this.settings);
}
@NonNull
diff --git a/lsp/java/src/main/java/com/itsaky/lsp/java/models/DefaultJavaServerSettings.java b/lsp/java/src/main/java/com/itsaky/lsp/java/models/DefaultJavaServerSettings.java
new file mode 100644
index 000000000..38571336c
--- /dev/null
+++ b/lsp/java/src/main/java/com/itsaky/lsp/java/models/DefaultJavaServerSettings.java
@@ -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 .
+ */
+
+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 {
+}
diff --git a/lsp/java/src/main/java/com/itsaky/lsp/java/providers/CompletionProvider.java b/lsp/java/src/main/java/com/itsaky/lsp/java/providers/CompletionProvider.java
index cfdee721f..8deeccda5 100644
--- a/lsp/java/src/main/java/com/itsaky/lsp/java/providers/CompletionProvider.java
+++ b/lsp/java/src/main/java/com/itsaky/lsp/java/providers/CompletionProvider.java
@@ -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 list = new ArrayList<> ();
Scope scope = trees.getScope(path);
- Predicate filter = name -> StringSearch.matchesPartialName(name, partial);
+ Predicate 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 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> 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 list = new ArrayList<> ();
Map> 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 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));
}
diff --git a/lsp/java/src/main/java/com/itsaky/lsp/java/utils/StringSearch.java b/lsp/java/src/main/java/com/itsaky/lsp/java/utils/StringSearch.java
index 78b0917fc..8e2f8ef9e 100644
--- a/lsp/java/src/main/java/com/itsaky/lsp/java/utils/StringSearch.java
+++ b/lsp/java/src/main/java/com/itsaky/lsp/java/utils/StringSearch.java
@@ -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);
}