From 1b50291f5b9739775fc760bcb4a11a34dca141dc Mon Sep 17 00:00:00 2001
From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com>
Date: Wed, 21 Jan 2026 01:11:37 +0000
Subject: [PATCH 01/43] fix(deps): update dependency
org.robolectric:robolectric to v4.16.1
---
gradle/libs.versions.toml | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml
index f240b419..c2d965a3 100644
--- a/gradle/libs.versions.toml
+++ b/gradle/libs.versions.toml
@@ -36,7 +36,7 @@ regex-onig = { module = "io.github.dingyi222666.regex-lib:regex-lib-oniguruma",
regex-re2j = { module = "io.github.dingyi222666.regex-lib:regex-lib-re2j", version = "1.0.2" }
tests-google-truth = { module = "com.google.truth:truth", version = "1.4.5" }
-tests-robolectric = { module = "org.robolectric:robolectric", version = "4.16" }
+tests-robolectric = { module = "org.robolectric:robolectric", version = "4.16.1" }
[plugins]
android-application = { id = "com.android.application", version.ref = "agp" }
From 6f67c6f4e2dd2eb198a97d590e7c609740b70f69 Mon Sep 17 00:00:00 2001
From: "Elliott Mac." <115413825+nullij@users.noreply.github.com>
Date: Tue, 3 Feb 2026 22:09:21 +0300
Subject: [PATCH 02/43] Update DefaultCompletionLayout.java
Fix ANR caused by infinite loop in DefaultCompletionLayout
Added iteration limits to prevent infinite loops in ensureListPositionVisible()
that could block the main thread and cause ANR crashes.
---
.../component/DefaultCompletionLayout.java | 33 +++++++++++++++++--
1 file changed, 31 insertions(+), 2 deletions(-)
diff --git a/editor/src/main/java/io/github/rosemoe/sora/widget/component/DefaultCompletionLayout.java b/editor/src/main/java/io/github/rosemoe/sora/widget/component/DefaultCompletionLayout.java
index e1d50cda..c26517da 100644
--- a/editor/src/main/java/io/github/rosemoe/sora/widget/component/DefaultCompletionLayout.java
+++ b/editor/src/main/java/io/github/rosemoe/sora/widget/component/DefaultCompletionLayout.java
@@ -28,6 +28,7 @@
import android.graphics.Outline;
import android.graphics.drawable.GradientDrawable;
import android.os.SystemClock;
+import android.util.Log;
import android.util.TypedValue;
import android.view.MotionEvent;
import android.view.View;
@@ -44,6 +45,15 @@
public class DefaultCompletionLayout implements CompletionLayout {
+ private static final String TAG = "DefaultCompletionLayout";
+
+ /**
+ * Maximum iterations for scroll operations to prevent infinite loops and ANR.
+ * This safety limit ensures that even if the scroll state becomes inconsistent,
+ * the UI thread won't be blocked indefinitely.
+ */
+ private static final int MAX_SCROLL_ITERATIONS = 100;
+
private ListView listView;
private ProgressBar progressBar;
private LinearLayout rootView;
@@ -194,11 +204,30 @@ public void ensureListPositionVisible(int position, int increment) {
listView.setSelectionFromTop(0, 0);
return;
}
- while (listView.getFirstVisiblePosition() + 1 > position && listView.canScrollList(-1)) {
+
+ // a FIX: Add iteration counters to prevent infinite loops that can cause ANR!!!
+ int upScrollIterations = 0;
+ while (listView.getFirstVisiblePosition() + 1 > position &&
+ listView.canScrollList(-1) &&
+ upScrollIterations < MAX_SCROLL_ITERATIONS) {
performScrollList(increment / 2);
+ upScrollIterations++;
}
- while (listView.getLastVisiblePosition() - 1 < position && listView.canScrollList(1)) {
+
+ int downScrollIterations = 0;
+ while (listView.getLastVisiblePosition() - 1 < position &&
+ listView.canScrollList(1) &&
+ downScrollIterations < MAX_SCROLL_ITERATIONS) {
performScrollList(-increment / 2);
+ downScrollIterations++;
+ }
+
+ // Log warning if we hit the iteration limit (indicates potential issue)
+ if (upScrollIterations >= MAX_SCROLL_ITERATIONS || downScrollIterations >= MAX_SCROLL_ITERATIONS) {
+ Log.w(TAG, "ensureListPositionVisible hit iteration limit: " +
+ "position=" + position +
+ ", upScrolls=" + upScrollIterations +
+ ", downScrolls=" + downScrollIterations);
}
});
}
From b3a8b1779899db4a637c55000409fb6604a1f3b4 Mon Sep 17 00:00:00 2001
From: Rosemoe <2073412493@qq.com>
Date: Fri, 6 Feb 2026 20:56:53 +0800
Subject: [PATCH 03/43] refact(editor): expose `variableResolver` for custom
variable resolver registration (close #801)
---
.../io/github/rosemoe/sora/widget/snippet/SnippetController.kt | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/editor/src/main/java/io/github/rosemoe/sora/widget/snippet/SnippetController.kt b/editor/src/main/java/io/github/rosemoe/sora/widget/snippet/SnippetController.kt
index 188c106c..34425a63 100644
--- a/editor/src/main/java/io/github/rosemoe/sora/widget/snippet/SnippetController.kt
+++ b/editor/src/main/java/io/github/rosemoe/sora/widget/snippet/SnippetController.kt
@@ -98,7 +98,7 @@ class SnippetController(private val editor: CodeEditor) {
private var currentTabStopIndex = -1
private var inSequenceEdits = false
- private val variableResolver = CompositeSnippetVariableResolver().also {
+ val variableResolver = CompositeSnippetVariableResolver().also {
it.addResolver(ClipboardBasedSnippetVariableResolver(editor.clipboardManager))
it.addResolver(EditorBasedSnippetVariableResolver(editor))
it.addResolver(RandomBasedSnippetVariableResolver())
From 533c6dcc2051fcbb7c1f88f06e4a8bc8c0ed7271 Mon Sep 17 00:00:00 2001
From: Rosemoe <2073412493@qq.com>
Date: Fri, 6 Feb 2026 20:57:48 +0800
Subject: [PATCH 04/43] chore(editor): refer to inlay hint type names in inlay
hint renderers
---
.../rosemoe/sora/graphics/inlayHint/ColorInlayHintRenderer.kt | 2 +-
.../rosemoe/sora/graphics/inlayHint/TextInlayHintRenderer.kt | 2 +-
2 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/editor/src/main/java/io/github/rosemoe/sora/graphics/inlayHint/ColorInlayHintRenderer.kt b/editor/src/main/java/io/github/rosemoe/sora/graphics/inlayHint/ColorInlayHintRenderer.kt
index 58e78fc5..5ec67410 100644
--- a/editor/src/main/java/io/github/rosemoe/sora/graphics/inlayHint/ColorInlayHintRenderer.kt
+++ b/editor/src/main/java/io/github/rosemoe/sora/graphics/inlayHint/ColorInlayHintRenderer.kt
@@ -43,7 +43,7 @@ open class ColorInlayHintRenderer(
}
override val typeName: String
- get() = "color"
+ get() = ColorInlayHint.TYPE_NAME
protected val localPaint = Paint().also {
it.isAntiAlias = true
diff --git a/editor/src/main/java/io/github/rosemoe/sora/graphics/inlayHint/TextInlayHintRenderer.kt b/editor/src/main/java/io/github/rosemoe/sora/graphics/inlayHint/TextInlayHintRenderer.kt
index d6920cbe..6f353460 100644
--- a/editor/src/main/java/io/github/rosemoe/sora/graphics/inlayHint/TextInlayHintRenderer.kt
+++ b/editor/src/main/java/io/github/rosemoe/sora/graphics/inlayHint/TextInlayHintRenderer.kt
@@ -70,7 +70,7 @@ open class TextInlayHintRenderer : InlayHintRenderer() {
protected val localPaint = Paint().also { it.isAntiAlias = true }
override val typeName: String
- get() = "text"
+ get() = TextInlayHint.TYPE_NAME
override fun onMeasure(
inlayHint: InlayHint,
From 0eff59f143744e8bb7d0abd42de214d37f625758 Mon Sep 17 00:00:00 2001
From: Rosemoe <2073412493@qq.com>
Date: Sun, 8 Feb 2026 12:26:30 +0800
Subject: [PATCH 05/43] fix(editor): add max text length for accessibility node
info Refer to newest `TextView` implementation. This settles OOM problem when
the content is too large.
(https://github.com/Xed-Editor/Xed-Editor/issues/1132)
---
.../github/rosemoe/sora/text/TextUtils.java | 12 ++++++++++
.../rosemoe/sora/widget/CodeEditor.java | 22 +++++++++++--------
.../sora/widget/DirectAccessProps.java | 11 ++++++++++
3 files changed, 36 insertions(+), 9 deletions(-)
diff --git a/editor/src/main/java/io/github/rosemoe/sora/text/TextUtils.java b/editor/src/main/java/io/github/rosemoe/sora/text/TextUtils.java
index 1f4b88ee..3e8a2852 100644
--- a/editor/src/main/java/io/github/rosemoe/sora/text/TextUtils.java
+++ b/editor/src/main/java/io/github/rosemoe/sora/text/TextUtils.java
@@ -23,7 +23,9 @@
*/
package io.github.rosemoe.sora.text;
+import androidx.annotation.IntRange;
import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
import java.util.Objects;
@@ -192,4 +194,14 @@ public static long findLeadingAndTrailingWhitespacePos(ContentLine line, int sta
}
return IntPair.pack(leading, trailing);
}
+
+ public static CharSequence trimToSize(@Nullable CharSequence text, @IntRange(from = 1) int size) {
+ if (size <= 0) throw new IllegalArgumentException("size must be bigger than 0");
+ if (text == null || text.length() <= size) return text;
+ if (Character.isHighSurrogate(text.charAt(size - 1))
+ && Character.isLowSurrogate(text.charAt(size))) {
+ size = size - 1;
+ }
+ return text.subSequence(0, size);
+ }
}
diff --git a/editor/src/main/java/io/github/rosemoe/sora/widget/CodeEditor.java b/editor/src/main/java/io/github/rosemoe/sora/widget/CodeEditor.java
index c9149117..445598d7 100644
--- a/editor/src/main/java/io/github/rosemoe/sora/widget/CodeEditor.java
+++ b/editor/src/main/java/io/github/rosemoe/sora/widget/CodeEditor.java
@@ -4720,16 +4720,20 @@ protected void onDraw(@NonNull Canvas canvas) {
public AccessibilityNodeInfo createAccessibilityNodeInfo() {
var info = super.createAccessibilityNodeInfo();
if (isEnabled()) {
- info.setEditable(isEditable());
- info.setTextSelection(cursor.getLeft(), cursor.getRight());
- info.setInputType(InputType.TYPE_CLASS_TEXT);
- info.setMultiLine(true);
- info.setText(getText().toStringBuilder());
+ var maxTextLength = props.maxAccessibilityTextLength;
+ if (maxTextLength > 0) {
+ info.setEditable(isEditable());
+ info.setTextSelection(cursor.getLeft(), cursor.getRight());
+ info.setInputType(InputType.TYPE_CLASS_TEXT);
+ info.setMultiLine(true);
+ info.setText(TextUtils.trimToSize(getText(), maxTextLength).toString());
+ info.addAction(AccessibilityNodeInfo.AccessibilityAction.ACTION_COPY);
+ info.addAction(AccessibilityNodeInfo.AccessibilityAction.ACTION_CUT);
+ info.addAction(AccessibilityNodeInfo.AccessibilityAction.ACTION_PASTE);
+ info.addAction(AccessibilityNodeInfo.AccessibilityAction.ACTION_SET_TEXT);
+ }
+
info.setLongClickable(true);
- info.addAction(AccessibilityNodeInfo.AccessibilityAction.ACTION_COPY);
- info.addAction(AccessibilityNodeInfo.AccessibilityAction.ACTION_CUT);
- info.addAction(AccessibilityNodeInfo.AccessibilityAction.ACTION_PASTE);
- info.addAction(AccessibilityNodeInfo.AccessibilityAction.ACTION_SET_TEXT);
final int scrollRange = getScrollMaxY();
if (scrollRange > 0) {
info.setScrollable(true);
diff --git a/editor/src/main/java/io/github/rosemoe/sora/widget/DirectAccessProps.java b/editor/src/main/java/io/github/rosemoe/sora/widget/DirectAccessProps.java
index f5f5e349..959bd0d4 100644
--- a/editor/src/main/java/io/github/rosemoe/sora/widget/DirectAccessProps.java
+++ b/editor/src/main/java/io/github/rosemoe/sora/widget/DirectAccessProps.java
@@ -152,6 +152,17 @@ public class DirectAccessProps implements Serializable {
@IntRange(from = 0)
public int maxIPCTextLength = 32768;
+ /**
+ * Max text length for accessibility node info. The text is packed into an
+ * {@link android.os.Parcel} and transferred to accessibility services.
+ *
+ * By default, we use the PARCEL_SAFE_TEXT_LENGTH value (100K) in {@link android.text.TextUtils}.
+ *
+ * If set to {@code 0}, the editor will not send any text related information to accessibility services.
+ */
+ @IntRange(from = 0)
+ public int maxAccessibilityTextLength = 100000;
+
/**
* Whether over scroll is permitted.
* When over scroll is enabled, the user will be able to scroll out of displaying
From 27a6cc4736f6e172a48616f72d83872a23889802 Mon Sep 17 00:00:00 2001
From: Rosemoe <2073412493@qq.com>
Date: Sun, 8 Feb 2026 16:05:49 +0800
Subject: [PATCH 06/43] build(app): migrate signing config to environment
variables * remove old keystore file * use newly-generated keystore from repo
secrets * use `signing.properties` for local dev environment * update app
version format in CI builds
---
.github/workflows/gradle.yml | 4 +
.gitignore | 4 +
app/build.gradle.kts | 47 +++++----
.../convention/src/main/kotlin/AppSigning.kt | 95 ++++++++++++++++++
.../convention/src/main/kotlin/Versions.kt | 8 +-
build.gradle.kts | 6 +-
debug.jks | Bin 2694 -> 0 bytes
7 files changed, 140 insertions(+), 24 deletions(-)
create mode 100644 build-logic/convention/src/main/kotlin/AppSigning.kt
delete mode 100644 debug.jks
diff --git a/.github/workflows/gradle.yml b/.github/workflows/gradle.yml
index 81dd6d74..424d9a77 100644
--- a/.github/workflows/gradle.yml
+++ b/.github/workflows/gradle.yml
@@ -53,6 +53,10 @@ jobs:
ORG_GRADLE_PROJECT_signingInMemoryKey: ${{ secrets.MVN_SIGNING_KEY }}
ORG_GRADLE_PROJECT_signingInMemoryKeyId: ${{ secrets.MVN_SIGNING_KEY_ID }}
ORG_GRADLE_PROJECT_signingInMemoryKeyPassword: ${{ secrets.MVN_SIGNING_KEY_PASSWORD }}
+ SIGNING_STORE_BIN: ${{ secrets.SIGNING_STORE_BIN }}
+ SIGNING_STORE_PASSWORD: ${{ secrets.SIGNING_STORE_PASSWORD }}
+ SIGNING_KEY_ALIAS: ${{ secrets.SIGNING_KEY_ALIAS }}
+ SIGNING_KEY_PASSWORD: ${{ secrets.SIGNING_KEY_PASSWORD }}
- name: Upload artifact
uses: actions/upload-artifact@v6
diff --git a/.gitignore b/.gitignore
index ecd80c7f..f5d8f702 100644
--- a/.gitignore
+++ b/.gitignore
@@ -91,3 +91,7 @@ lint/generated/
lint/outputs/
lint/tmp/
# lint/reports/
+
+# Local Signing Config
+signing.properties
+signing.keystore
\ No newline at end of file
diff --git a/app/build.gradle.kts b/app/build.gradle.kts
index ba369ca2..5f446ddd 100644
--- a/app/build.gradle.kts
+++ b/app/build.gradle.kts
@@ -27,43 +27,53 @@ plugins {
}
android {
+ namespace = "io.github.rosemoe.sora.app"
+
defaultConfig {
applicationId = "io.github.rosemoe.sora.app"
testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
- versionCode = Versions.versionCode
- versionName = Versions.versionName + "-" + System.currentTimeMillis()
}
+
signingConfigs {
- create("general") {
- storeFile = file("../debug.jks")
- storePassword = "114514"
- keyAlias = "debug"
- keyPassword = "114514"
- enableV1Signing = true
- enableV2Signing = true
- }
+ AppSigning.getAppSigningConfigOptional(project)
+ .onSuccess {
+ create("general") {
+ storeFile = it.storeFile
+ storePassword = it.storePassword
+ keyAlias = it.keyAlias
+ keyPassword = it.keyPassword
+
+ enableV1Signing = true
+ enableV2Signing = true
+ }
+
+ buildTypes.forEach { buildType ->
+ buildType.signingConfig = signingConfigs.getByName("general")
+ }
+ }.onFailure {
+ logger.error("Failed to get signing config. Signing configuration is left as is.")
+ }
}
- buildTypes {
- release {
- isMinifyEnabled = false
- signingConfig = signingConfigs.getByName("general")
- proguardFiles("proguard-rules.pro")
- }
- debug {
+
+ for (buildType in buildTypes) {
+ buildType.apply {
isMinifyEnabled = false
- signingConfig = signingConfigs.getByName("general")
proguardFiles("proguard-rules.pro")
}
}
+
compileOptions {
isCoreLibraryDesugaringEnabled = true
}
+
androidResources {
additionalParameters.add("--warn-manifest-validation")
}
+
buildFeatures {
viewBinding = true
}
+
packaging {
resources.pickFirsts.addAll(
arrayOf(
@@ -75,7 +85,6 @@ android {
)
)
}
- namespace = "io.github.rosemoe.sora.app"
}
dependencies {
diff --git a/build-logic/convention/src/main/kotlin/AppSigning.kt b/build-logic/convention/src/main/kotlin/AppSigning.kt
new file mode 100644
index 00000000..527789a5
--- /dev/null
+++ b/build-logic/convention/src/main/kotlin/AppSigning.kt
@@ -0,0 +1,95 @@
+/*******************************************************************************
+ * sora-editor - the awesome code editor for Android
+ * https://github.com/Rosemoe/sora-editor
+ * Copyright (C) 2020-2026 Rosemoe
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
+ * USA
+ *
+ * Please contact Rosemoe by email 2073412493@qq.com if you need
+ * additional information or have any questions
+ ******************************************************************************/
+
+import org.gradle.api.Project
+import java.io.File
+import java.util.Base64
+import java.util.Properties
+
+/**
+ * Signing config for application
+ */
+object AppSigning {
+
+ data class AppSigningConfig(
+ val storeFile: File,
+ val storePassword: String,
+ val keyAlias: String,
+ val keyPassword: String
+ )
+
+ fun getAppSigningConfigOptional(project: Project): Result = runCatching {
+ getAppSigningConfig(project)
+ }.onFailure {
+ val message = when (it) {
+ is MissingEnvVarException -> "App signing config not correctly configured"
+ else -> "Error when generating app signing config"
+ }
+ project.logger.error(message, it)
+ }
+
+ fun getAppSigningConfig(project: Project): AppSigningConfig {
+ val properties = Properties().also {
+ val file = project.rootProject.file("signing.properties")
+ if (file.exists()) {
+ file.reader().use { rd ->
+ it.load(rd)
+ }
+ }
+ }
+ val storeFile = project.rootProject.file("signing.keystore")
+
+ val storeBin = getEnvOrProp(properties, "SIGNING_STORE_BIN")
+ val storePassword = getEnvOrProp(properties, "SIGNING_STORE_PASSWORD")
+ val keyAlias = getEnvOrProp(properties, "SIGNING_KEY_ALIAS")
+ val keyPassword = getEnvOrProp(properties, "SIGNING_KEY_PASSWORD")
+
+ val keystoreData = Base64.getDecoder().decode(storeBin)
+ storeFile.parentFile.mkdirs()
+ storeFile.createNewFile()
+ storeFile.writeBytes(keystoreData)
+
+ return AppSigningConfig(
+ storeFile = storeFile,
+ storePassword = storePassword,
+ keyAlias = keyAlias,
+ keyPassword = keyPassword
+ )
+ }
+
+ private fun getEnvOrProp(properties: Properties, key: String): String {
+ var value: String? = System.getenv(key)
+ if (value.isNullOrBlank()) {
+ value = properties[key] as? String?
+ }
+
+ if (value.isNullOrBlank()) {
+ throw MissingEnvVarException("`$key` is not set in environment variables or properties")
+ }
+ return value
+ }
+
+ class MissingEnvVarException(msg: String) : Exception(msg)
+
+}
\ No newline at end of file
diff --git a/build-logic/convention/src/main/kotlin/Versions.kt b/build-logic/convention/src/main/kotlin/Versions.kt
index 65f4e2ad..544bd4e5 100644
--- a/build-logic/convention/src/main/kotlin/Versions.kt
+++ b/build-logic/convention/src/main/kotlin/Versions.kt
@@ -27,7 +27,13 @@ object Versions {
private const val version = "0.24.4"
const val versionCode = 93
- val versionName by lazy {
+ val appVersionName by lazy {
+ if (CI.isCiBuild) {
+ "$version-${CI.commitHash}"
+ } else "$version-${System.currentTimeMillis()}"
+ }
+
+ val artifactVersion by lazy {
if (CI.isCiBuild) {
"$version-SNAPSHOT"
} else version
diff --git a/build.gradle.kts b/build.gradle.kts
index 7d40186e..034ae38b 100644
--- a/build.gradle.kts
+++ b/build.gradle.kts
@@ -61,7 +61,7 @@ fun Project.configureAndroidAndKotlin() {
defaultConfig {
targetSdk = Versions.targetSdkVersion
versionCode = Versions.versionCode
- versionName = Versions.versionName
+ versionName = Versions.appVersionName
}
}
@@ -75,7 +75,7 @@ fun Project.configureAndroidAndKotlin() {
subprojects {
group = "io.github.rosemoe"
- version = Versions.versionName
+ version = Versions.artifactVersion
plugins.withId("com.android.application") {
configureAndroidAndKotlin()
@@ -86,8 +86,6 @@ subprojects {
plugins.withId("com.vanniktech.maven.publish.base") {
configure {
- group = "io.github.rosemoe"
- version = Versions.versionName
pomFromGradleProperties()
publishToMavenCentral()
signAllPublications()
diff --git a/debug.jks b/debug.jks
deleted file mode 100644
index ce0047dfd9c48cd5a79635f0a5837a48a08b3bb4..0000000000000000000000000000000000000000
GIT binary patch
literal 0
HcmV?d00001
literal 2694
zcma);X*d*&7RP6|41);SHTETA$u7%V3?=(ovN!fu5-Md(mKcMf$-c`nh@@_^>dArZOPw#U--TUD@=Q+Rs`Ja#f=b&)RI1mtw!ZFLim}FwmF}til24Fsp
zSrCF_KJyEoM&Y29|0O|lAUJ5oFHHJXL>T-(E*54WC?5ya`vtX8H-9^ztSASR`adHJ
zN*2Neo6E})#oE11#Y-2t0eu42cS^NDAW3!*Pz1#SWBm6;5EB%D5`;0i#GrwmU6Rpcm0-Sq`dP(Isj5kh%@&UTZcyW(u9w`Kf~KtzG)8~L5D3N_a02C4ym
zbn`tiD$w7+?h814*s#tBKTD$B3(|R{%Xp^ZK)0v2V!z6_^ImY`F*=mz(2NZ&pJ
ztw<&xP5a&<>U39WHbT}3tv7(Z6&V&>3Z?eadp+%IK;t2Oj>A=
z3er&DLfkVWDc2%QKo_7Y)kU1$=;l)%2@D-^Z#c$m-^T?~J_oo*L6jLo9KD{aoWrRu?63M|
zGWma1{Z@9iIk6BSzgFNamz=I*eE+(neLB0Q$T2sk;Ef(;H9l(Fw@gu_bEKKq_6omO
zX)MR$gWQG0)SJUqB~J8>A-w2lMJN`ZwCQTg=t7qHg@iiS|!u#G_=?K&pNpwse@i6
zp8h<70pmiA%O=DlraRcDtFVAcc$e3}HnV%3d<%n*+&CH7!V!};yCk~$)$e(`KCZa>
z`%pjyRqsML>6Eu=x0i;=kDlh@nbdkR^<(M>S_*WbH@6k*eQlN}=ecx5TYyR8gJU_4
zw|z=roUf!VLrF#wdC!nZ@RJrtgGA0w70hI;m}WG6nwBYiu7=Wm~0>r6CZ=(J9hqg5(J?S@6z|yQF?B<
zN#a(W516g&W@hL1Rk#IUevCY-j6V)T#^SIVkdhRBA!EmZjt+VK&Za-7@*JJI@*8el
z3|72=I`ca&nYa{LgqQ&y08fA$;0^$T68%Ryt;hvAW$o?nDWa&Vs)o`~M=7c(DJr3G
z5ZB*J46uA0#PS!q3IYOtHKTtN;QtC~j_t+CCqP~Zfdq-sDyZDyO^18`KOr6VtXxgW
zC4x$*Htm4Z9wD$e@Q1q*VN(|OQVJF45S^&lSoKQs$?I$2na!|K@M(o{trhIMp_W?BO-`kbuUSFPhLz2Y#ZHLmYfa-w(q
zbIRt?fo{vwX2-DBi${!^1fth?kZ`K~;D%bk(SA0b#5wo&ZV&H6rmH``JVo>fXXe>_
zGn*^Td_!}hB3Fow*>Od|(M8!ANgFJ%^iz>9uRd#$(vEec5S$p>IiknGZN|Pcy@~@&
zk}%Aoe{nK=dBUgN6@D~VJ-Xad$|l|VCvXz4HxvJIWLHS5c=;v!>rZxS+*4{#C*`}b
zN~S{;w=@h;UPG)_MP9&=b|WzKhpKHw?JHq@WdYPzCp+pD?5z86+U|g7eb?n^Rttv$
zHfxzCpH$(yAvy=wO*~qxrYI8jQDm4N{jZ(yW~3=k_0;-#LMHU?E;2Z}oV&{Y#U
zXp)4w*jvQHY!CsMV%P_gsbsYWUTCT7Dm=N}5w8&pgw-hvxu|{Ow=&Q(fBMlQJWOwL
zugspJHtp1?b}2_YdHNlc6ymMLq2+P;{-&+w=L|b+Yl2VknT^$4TSnt7S1vP++PwkGm^Y>%5m0s^tX~#g
z)XBUC(>9uzG->w7$Fi|BE>1C!#1nT8!S&0zA2{F-W=#)lZ^q`IbF)mlCh5Y(wERbj
zrqVD~ADM3**ef}tS}Ycz;e1=cG0d#+FyP(n3QJ?zM|IR6UMn`|JJDZ3=QS`ZF+0J7
z$Ct``zl{ZlfE#}r=3KxB5JeRAUm^sy7!oV~HlX59-cS@lQ~kL%jI=gKxha
zB(Nz6oN2s=x%@%bLa^<4?0#|-FVHxq3c5cxt)F|a@!*Aof!2EYFjXt|
zZvP<46s3q_{r#JPfKUKLeE<0lq?CB4D|9Pn_J)OUvFo$S*AOlj
b;_K8K)6HR
Date: Sun, 8 Feb 2026 16:13:36 +0800
Subject: [PATCH 07/43] build(app): move signing config vars to job-level env
---
.github/workflows/gradle.yml | 9 +++++----
1 file changed, 5 insertions(+), 4 deletions(-)
diff --git a/.github/workflows/gradle.yml b/.github/workflows/gradle.yml
index 424d9a77..cfb7b381 100644
--- a/.github/workflows/gradle.yml
+++ b/.github/workflows/gradle.yml
@@ -17,6 +17,11 @@ jobs:
build:
name: Build debug APK
runs-on: ubuntu-latest
+ env:
+ SIGNING_STORE_BIN: ${{ secrets.SIGNING_STORE_BIN }}
+ SIGNING_STORE_PASSWORD: ${{ secrets.SIGNING_STORE_PASSWORD }}
+ SIGNING_KEY_ALIAS: ${{ secrets.SIGNING_KEY_ALIAS }}
+ SIGNING_KEY_PASSWORD: ${{ secrets.SIGNING_KEY_PASSWORD }}
steps:
- name: Cancel Previous Runs
uses: styfle/cancel-workflow-action@0.13.0
@@ -53,10 +58,6 @@ jobs:
ORG_GRADLE_PROJECT_signingInMemoryKey: ${{ secrets.MVN_SIGNING_KEY }}
ORG_GRADLE_PROJECT_signingInMemoryKeyId: ${{ secrets.MVN_SIGNING_KEY_ID }}
ORG_GRADLE_PROJECT_signingInMemoryKeyPassword: ${{ secrets.MVN_SIGNING_KEY_PASSWORD }}
- SIGNING_STORE_BIN: ${{ secrets.SIGNING_STORE_BIN }}
- SIGNING_STORE_PASSWORD: ${{ secrets.SIGNING_STORE_PASSWORD }}
- SIGNING_KEY_ALIAS: ${{ secrets.SIGNING_KEY_ALIAS }}
- SIGNING_KEY_PASSWORD: ${{ secrets.SIGNING_KEY_PASSWORD }}
- name: Upload artifact
uses: actions/upload-artifact@v6
From 9f20f82580153679c0105b38bcd9a9403394d17d Mon Sep 17 00:00:00 2001
From: Rosemoe <2073412493@qq.com>
Date: Sun, 8 Feb 2026 16:58:34 +0800
Subject: [PATCH 08/43] docs(textmate): update README.md for TextMate
---
language-textmate/README.md | 41 +++++++++++++++++++++++++++----------
1 file changed, 30 insertions(+), 11 deletions(-)
diff --git a/language-textmate/README.md b/language-textmate/README.md
index c76edbe4..ee4011d2 100644
--- a/language-textmate/README.md
+++ b/language-textmate/README.md
@@ -1,15 +1,34 @@
-## About
+# TextMate Support
-**Work In Progress** `language-textmate` module is a module that performs syntax highlighting and other functions dynamically. To use it, you need to introduce several other `textmate-*` modules.Our goal is to achieve the effect of VSCode. However, for many reasons, this may be difficult to achieve in the short term.
+## Overview
-## Features(already available)
+This module provide language support and theme configuration based
+on [TextMate](https://macromates.com/) rule files.
-1. Highlighting of files based on syntax rules
-2. Load color theme from file
-3. Code block line based on indent and rule
+The core implementation of TextMate functionality is
+from [tm4e](https://github.com/eclipse-tm4e/tm4e).
-## How to get syntax and theme files
-If many people use this module, they may collect the available configuration files into a repository later.
-- You can obtain relevant documents from [Textmate](https://github.com/textmate).
-- Eclipse also uses Textmate, and you can also get files from its related repository。
-- Textmate is also used in [vscode](https://github.com/microsoft/vscode/tree/main/extensions), but its version is ahead of the version used in this module. You can get the configuration file from its source code, but not all of them can be used normally
\ No newline at end of file
+## Features
+
+* MultiLanguage Registry
+* Syntax Highlighting based on TextMate Grammars
+* TextMate Themes
+* Folding Regions
+* Indentation Rules
+* Symbol Pair Auto-Completion
+
+## Language Bundles and Themes
+
+We do not currently maintain a repository of TextMate language bundles and themes.
+
+- You can obtain relevant documents from [TextMate Projects](https://github.com/textmate).
+- Eclipse also uses TextMate, and you can also get files from its related repository.
+- TextMate is also used in [VSCode](https://github.com/microsoft/vscode/tree/main/extensions).
+ You can get the configuration file from its source code
+ - We don't guarantee that all language bundles can be correctly analyzed, due to regex library
+ difference
+ - Include `oniguruma-native` module to use the same regex library as VSCode
+
+Read
+our [documentation](https://project-sora.github.io/sora-editor-docs/guide/using-language#language-textmate)
+for more information.
\ No newline at end of file
From efbacacd2a624dcec38c946d85d4db541abd34a2 Mon Sep 17 00:00:00 2001
From: Rosemoe <2073412493@qq.com>
Date: Sun, 8 Feb 2026 23:21:37 +0800
Subject: [PATCH 09/43] fix(editor): `SymbolInputView` always overrides the
background defined in XML
---
.../java/io/github/rosemoe/sora/widget/SymbolInputView.java | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/editor/src/main/java/io/github/rosemoe/sora/widget/SymbolInputView.java b/editor/src/main/java/io/github/rosemoe/sora/widget/SymbolInputView.java
index e12f6075..3ed529c0 100644
--- a/editor/src/main/java/io/github/rosemoe/sora/widget/SymbolInputView.java
+++ b/editor/src/main/java/io/github/rosemoe/sora/widget/SymbolInputView.java
@@ -69,7 +69,9 @@ public SymbolInputView(Context context, AttributeSet attrs, int defStyleAttr, in
}
private void init() {
- setBackgroundColor(getContext().getResources().getColor(R.color.defaultSymbolInputBackgroundColor));
+ if (getBackground() == null) {
+ setBackgroundColor(getContext().getResources().getColor(R.color.defaultSymbolInputBackgroundColor));
+ }
setOrientation(HORIZONTAL);
setTextColor(getContext().getResources().getColor(R.color.defaultSymbolInputTextColor));
}
From 099b8be2f5da32dac24d730a2758948296822273 Mon Sep 17 00:00:00 2001
From: Rosemoe <2073412493@qq.com>
Date: Mon, 9 Feb 2026 00:02:26 +0800
Subject: [PATCH 10/43] refact(app): migrate to Material 3 * use Material 3
themes and widgets (partially) * always enable edge-to-edge * fix padding for
bottom insets * activity no longer consumes `uiMode` configuration changes
---
app/src/main/AndroidManifest.xml | 9 +-
app/src/main/assets/samples/sample.txt | 22 +--
.../rosemoe/sora/app/BaseEditorActivity.java | 2 +-
.../rosemoe/sora/app/EditorApplication.kt | 37 +++++
.../github/rosemoe/sora/app/MainActivity.kt | 67 ++++++--
.../java/io/github/rosemoe/sora/app/Utils.kt | 30 ++--
app/src/main/res/layout/activity_editor.xml | 9 +-
app/src/main/res/layout/activity_main.xml | 12 +-
app/src/main/res/values-night/colors.xml | 143 ++++++++++++++++
app/src/main/res/values-night/styles.xml | 33 ----
.../main/res/values-night/theme_overlays.xml | 153 ++++++++++++++++++
app/src/main/res/values-night/themes.xml | 75 +++++++++
app/src/main/res/values/colors.xml | 148 ++++++++++++++++-
app/src/main/res/values/styles.xml | 38 -----
app/src/main/res/values/theme_overlays.xml | 153 ++++++++++++++++++
app/src/main/res/values/themes.xml | 75 +++++++++
16 files changed, 861 insertions(+), 145 deletions(-)
create mode 100644 app/src/main/java/io/github/rosemoe/sora/app/EditorApplication.kt
create mode 100644 app/src/main/res/values-night/colors.xml
delete mode 100644 app/src/main/res/values-night/styles.xml
create mode 100644 app/src/main/res/values-night/theme_overlays.xml
create mode 100644 app/src/main/res/values-night/themes.xml
delete mode 100644 app/src/main/res/values/styles.xml
create mode 100644 app/src/main/res/values/theme_overlays.xml
create mode 100644 app/src/main/res/values/themes.xml
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index 4ac03332..48338e8a 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -37,6 +37,7 @@
android:networkSecurityConfig="@xml/network_security_config"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
+ android:name=".EditorApplication"
android:theme="@style/AppTheme">
diff --git a/app/src/main/assets/samples/sample.txt b/app/src/main/assets/samples/sample.txt
index 32811859..fbf1b010 100644
--- a/app/src/main/assets/samples/sample.txt
+++ b/app/src/main/assets/samples/sample.txt
@@ -1,25 +1,5 @@
/*
- * sora-editor - the awesome code editor for Android
- * https://github.com/Rosemoe/sora-editor
- * Copyright (C) 2020-2022 Rosemoe
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
- *
- * This library 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
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
- * USA
- *
- * Please contact Rosemoe by email 2073412493@qq.com if you need
- * additional information or have any questions
+ * Sample Java source file.
*/
package io.github.rosemoe.sora.util;
diff --git a/app/src/main/java/io/github/rosemoe/sora/app/BaseEditorActivity.java b/app/src/main/java/io/github/rosemoe/sora/app/BaseEditorActivity.java
index 2fa4c827..621ae8e5 100644
--- a/app/src/main/java/io/github/rosemoe/sora/app/BaseEditorActivity.java
+++ b/app/src/main/java/io/github/rosemoe/sora/app/BaseEditorActivity.java
@@ -47,7 +47,7 @@ protected void onCreate(@Nullable Bundle savedInstanceState) {
setContentView(binding.getRoot());
setSupportActionBar(binding.activityToolbar);
- UtilsKt.applyEdgeToEdgeForViews(binding.toolbarContainer, binding.getRoot());
+ UtilsKt.applyEdgeToEdge(this, binding.toolbarContainer, binding.getRoot());
var supportActionBar = getSupportActionBar();
if (supportActionBar != null) {
diff --git a/app/src/main/java/io/github/rosemoe/sora/app/EditorApplication.kt b/app/src/main/java/io/github/rosemoe/sora/app/EditorApplication.kt
new file mode 100644
index 00000000..6f6a577a
--- /dev/null
+++ b/app/src/main/java/io/github/rosemoe/sora/app/EditorApplication.kt
@@ -0,0 +1,37 @@
+/*******************************************************************************
+ * sora-editor - the awesome code editor for Android
+ * https://github.com/Rosemoe/sora-editor
+ * Copyright (C) 2020-2026 Rosemoe
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
+ * USA
+ *
+ * Please contact Rosemoe by email 2073412493@qq.com if you need
+ * additional information or have any questions
+ ******************************************************************************/
+
+package io.github.rosemoe.sora.app
+
+import android.app.Application
+import com.google.android.material.color.DynamicColors
+
+class EditorApplication : Application() {
+
+ override fun onCreate() {
+ super.onCreate()
+ DynamicColors.applyToActivitiesIfAvailable(this)
+ }
+
+}
\ No newline at end of file
diff --git a/app/src/main/java/io/github/rosemoe/sora/app/MainActivity.kt b/app/src/main/java/io/github/rosemoe/sora/app/MainActivity.kt
index 28b422cd..6ecdbfa1 100644
--- a/app/src/main/java/io/github/rosemoe/sora/app/MainActivity.kt
+++ b/app/src/main/java/io/github/rosemoe/sora/app/MainActivity.kt
@@ -23,13 +23,13 @@
******************************************************************************/
package io.github.rosemoe.sora.app
-import android.app.AlertDialog
import android.content.DialogInterface
import android.content.res.Configuration
import android.graphics.Typeface
import android.net.Uri
import android.os.Build
import android.os.Bundle
+import android.os.PersistableBundle
import android.text.Editable
import android.text.TextWatcher
import android.util.Log
@@ -41,7 +41,10 @@ import android.widget.PopupMenu
import android.widget.Toast
import androidx.activity.result.contract.ActivityResultContracts.GetContent
import androidx.appcompat.app.AppCompatActivity
+import androidx.core.view.ViewCompat
import androidx.lifecycle.lifecycleScope
+import androidx.savedstate.write
+import com.google.android.material.dialog.MaterialAlertDialogBuilder
import io.github.dingyi222666.monarch.languages.JavaLanguage
import io.github.dingyi222666.monarch.languages.KotlinLanguage
import io.github.dingyi222666.monarch.languages.PythonLanguage
@@ -165,7 +168,7 @@ class MainActivity : AppCompatActivity() {
setContentView(binding.root)
setSupportActionBar(binding.activityToolbar)
- applyEdgeToEdgeForViews(binding.toolbarContainer, binding.root)
+ applyEdgeToEdge(this, binding.toolbarContainer, binding.root)
val typeface = Typeface.createFromAsset(assets, "JetBrainsMono-Regular.ttf")
@@ -284,8 +287,37 @@ class MainActivity : AppCompatActivity() {
)
editor.setEditorLanguage(language)
- // Open assets file
- openAssetsFile("samples/sample.txt")
+ val savedText = savedInstanceState?.getString("text")
+ if (savedText != null) {
+ val textSize = savedInstanceState.getFloat("font.size")
+ if (textSize > 0f) {
+ editor.textSizePx = textSize
+ }
+ editor.setText(savedText)
+ val left = savedInstanceState.getInt("position.left").coerceIn(0, editor.text.length)
+ val right = savedInstanceState.getInt("position.right").coerceIn(0, editor.text.length)
+ val leftPos = editor.text.indexer.getCharPosition(left.coerceAtMost(right))
+ val rightPos = editor.text.indexer.getCharPosition(right.coerceAtLeast(left))
+ editor.setSelectionRegion(
+ leftPos.line,
+ leftPos.column,
+ rightPos.line,
+ rightPos.column,
+ false
+ )
+ editor.scroller.startScroll(
+ savedInstanceState.getInt("scroll.x"),
+ savedInstanceState.getInt("scroll.y"),
+ 0,
+ 0,
+ 0
+ )
+ editor.scroller.abortAnimation()
+ editor.postInvalidate()
+ } else {
+ // Open assets file
+ openAssetsFile("samples/sample.txt")
+ }
updatePositionText()
updateBtnState()
@@ -623,9 +655,16 @@ class MainActivity : AppCompatActivity() {
binding.positionDisplay.text = text
}
- override fun onConfigurationChanged(newConfig: Configuration) {
- super.onConfigurationChanged(newConfig)
- switchThemeIfRequired(this, binding.editor)
+ override fun onSaveInstanceState(outState: Bundle) {
+ super.onSaveInstanceState(outState)
+ outState.write {
+ putString("text", binding.editor.text.toString())
+ putFloat("font.size", binding.editor.textSizePx)
+ putInt("position.left", binding.editor.cursor.left)
+ putInt("position.right", binding.editor.cursor.right)
+ putInt("scroll.x", binding.editor.offsetX)
+ putInt("scroll.y", binding.editor.offsetY)
+ }
}
override fun onCreateOptionsMenu(menu: Menu): Boolean {
@@ -647,13 +686,13 @@ class MainActivity : AppCompatActivity() {
R.id.open_test_activity -> startActivity()
R.id.open_lsp_activity -> {
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O) {
- AlertDialog.Builder(this)
+ MaterialAlertDialogBuilder(this)
.setTitle(getString(R.string.not_supported))
.setMessage(getString(R.string.dialog_api_warning_msg))
.setPositiveButton(android.R.string.ok, null)
.show()
} else {
- AlertDialog.Builder(this)
+ MaterialAlertDialogBuilder(this)
.setTitle(R.string.dialog_lsp_entry_title)
.setMessage(R.string.dialog_lsp_entry_msg)
.setPositiveButton(R.string.choice_yes) { _, _ ->
@@ -698,7 +737,7 @@ class MainActivity : AppCompatActivity() {
getString(R.string.center),
getString(R.string.bottom)
)
- AlertDialog.Builder(this)
+ MaterialAlertDialogBuilder(this)
.setTitle(R.string.fixed)
.setSingleChoiceItems(themes, -1) { dialog: DialogInterface, which: Int ->
editor.lnPanelPositionMode = LineInfoPanelPositionMode.FOLLOW
@@ -781,7 +820,7 @@ class MainActivity : AppCompatActivity() {
"Ubuntu-Regular.ttf",
"Roboto-Regular.ttf"
)
- AlertDialog.Builder(this)
+ MaterialAlertDialogBuilder(this)
.setTitle(android.R.string.dialog_alert_title)
.setSingleChoiceItems(fonts, -1) { dialog: DialogInterface, which: Int ->
if (which in assetsPaths.indices) {
@@ -807,7 +846,7 @@ class MainActivity : AppCompatActivity() {
getString(R.string.bottom_left),
getString(R.string.bottom_right)
)
- AlertDialog.Builder(this)
+ MaterialAlertDialogBuilder(this)
.setTitle(R.string.fixed)
.setSingleChoiceItems(themes, -1) { dialog: DialogInterface, which: Int ->
editor.lnPanelPositionMode = LineInfoPanelPositionMode.FIXED
@@ -905,7 +944,7 @@ class MainActivity : AppCompatActivity() {
"Monarch TypeScript" to "source.typescript"
)
- AlertDialog.Builder(this)
+ MaterialAlertDialogBuilder(this)
.setTitle(R.string.switch_language)
.setSingleChoiceItems(languageOptions, -1) { dialog: DialogInterface, which: Int ->
when (val selected = languageOptions[which]) {
@@ -991,7 +1030,7 @@ class MainActivity : AppCompatActivity() {
"Solarized(Dark) for TM(VSCode)",
"TM theme from file"
)
- AlertDialog.Builder(this)
+ MaterialAlertDialogBuilder(this)
.setTitle(R.string.color_scheme)
.setSingleChoiceItems(themes, -1) { dialog: DialogInterface, which: Int ->
when (which) {
diff --git a/app/src/main/java/io/github/rosemoe/sora/app/Utils.kt b/app/src/main/java/io/github/rosemoe/sora/app/Utils.kt
index cffea432..ca1c6821 100644
--- a/app/src/main/java/io/github/rosemoe/sora/app/Utils.kt
+++ b/app/src/main/java/io/github/rosemoe/sora/app/Utils.kt
@@ -28,11 +28,12 @@ import android.app.Activity
import android.content.Context
import android.content.Intent
import android.content.res.Configuration
-import android.os.Build
-import android.os.Build.VERSION.SDK_INT
import android.view.View
+import androidx.activity.enableEdgeToEdge
+import androidx.appcompat.app.AppCompatActivity
import androidx.core.view.ViewCompat
import androidx.core.view.WindowInsetsCompat
+import androidx.core.view.updatePadding
import io.github.rosemoe.sora.langs.monarch.MonarchColorScheme
import io.github.rosemoe.sora.langs.textmate.TextMateColorScheme
import io.github.rosemoe.sora.langs.textmate.registry.ThemeRegistry
@@ -40,8 +41,11 @@ import io.github.rosemoe.sora.widget.CodeEditor
import io.github.rosemoe.sora.widget.schemes.EditorColorScheme
import io.github.rosemoe.sora.widget.schemes.SchemeDarcula
+fun Context.isNightMode(): Boolean =
+ (resources.configuration.uiMode and Configuration.UI_MODE_NIGHT_MASK) == Configuration.UI_MODE_NIGHT_YES
+
fun switchThemeIfRequired(context: Context, editor: CodeEditor) {
- if ((context.resources.configuration.uiMode and Configuration.UI_MODE_NIGHT_MASK) == Configuration.UI_MODE_NIGHT_YES) {
+ if (context.isNightMode()) {
if (editor.colorScheme is TextMateColorScheme) {
ThemeRegistry.getInstance().setTheme("darcula")
} else if (editor.colorScheme is MonarchColorScheme) {
@@ -66,16 +70,16 @@ inline fun Context.startActivity() {
}
/**
- * Adjust the top padding of view to the height of status bar due to edge-to-edge since API 35
+ * Enable edge-to-edge and apply paddings
*/
-fun applyEdgeToEdgeForViews(paddingView: View, rootView: View) {
- if (SDK_INT >= Build.VERSION_CODES.VANILLA_ICE_CREAM) {
- ViewCompat.setOnApplyWindowInsetsListener(paddingView) { v, insets ->
- val statusBar = insets.getInsets(WindowInsetsCompat.Type.statusBars())
- v.setPadding(0, statusBar.top, 0, 0)
- val ime = insets.getInsets(WindowInsetsCompat.Type.ime())
- rootView.setPadding(0, 0, 0, ime.bottom)
- insets
- }
+fun applyEdgeToEdge(activity: AppCompatActivity, topPaddingView: View, rootView: View) {
+ activity.enableEdgeToEdge()
+ ViewCompat.setOnApplyWindowInsetsListener(rootView) { _, insets ->
+ val systemWindowInsets = insets.getInsets(
+ WindowInsetsCompat.Type.systemBars() or WindowInsetsCompat.Type.ime()
+ )
+ topPaddingView.updatePadding(top = systemWindowInsets.top)
+ rootView.updatePadding(bottom = systemWindowInsets.bottom)
+ insets
}
}
diff --git a/app/src/main/res/layout/activity_editor.xml b/app/src/main/res/layout/activity_editor.xml
index ba49ae4c..11a4dec8 100644
--- a/app/src/main/res/layout/activity_editor.xml
+++ b/app/src/main/res/layout/activity_editor.xml
@@ -28,21 +28,18 @@
android:layout_height="match_parent"
android:orientation="vertical">
-
-
+
-
-
-
-
+
diff --git a/app/src/main/res/values-night/colors.xml b/app/src/main/res/values-night/colors.xml
new file mode 100644
index 00000000..8bf845d8
--- /dev/null
+++ b/app/src/main/res/values-night/colors.xml
@@ -0,0 +1,143 @@
+
+ #AAC7FF
+ #0A305F
+ #284777
+ #D6E3FF
+ #BEC6DC
+ #283141
+ #3E4759
+ #DAE2F9
+ #DDBCE0
+ #3F2844
+ #573E5C
+ #FAD8FD
+ #FFB4AB
+ #690005
+ #93000A
+ #FFDAD6
+ #111318
+ #E2E2E9
+ #111318
+ #E2E2E9
+ #44474E
+ #C4C6D0
+ #8E9099
+ #44474E
+ #000000
+ #E2E2E9
+ #2E3036
+ #415F91
+ #D6E3FF
+ #001B3E
+ #AAC7FF
+ #284777
+ #DAE2F9
+ #131C2B
+ #BEC6DC
+ #3E4759
+ #FAD8FD
+ #28132E
+ #DDBCE0
+ #573E5C
+ #111318
+ #37393E
+ #0C0E13
+ #191C20
+ #1D2024
+ #282A2F
+ #33353A
+ #CDDDFF
+ #002551
+ #7491C7
+ #000000
+ #D4DCF2
+ #1D2636
+ #8891A5
+ #000000
+ #F3D2F7
+ #331D39
+ #A487A9
+ #000000
+ #FFD2CC
+ #540003
+ #FF5449
+ #000000
+ #111318
+ #E2E2E9
+ #111318
+ #FFFFFF
+ #44474E
+ #DADCE6
+ #AFB2BB
+ #8E9099
+ #000000
+ #E2E2E9
+ #282A2F
+ #294878
+ #D6E3FF
+ #00112B
+ #AAC7FF
+ #133665
+ #DAE2F9
+ #081121
+ #BEC6DC
+ #2E3647
+ #FAD8FD
+ #1D0823
+ #DDBCE0
+ #452E4A
+ #111318
+ #43444A
+ #06070C
+ #1B1E22
+ #26282D
+ #313238
+ #3C3E43
+ #EBF0FF
+ #000000
+ #A6C3FC
+ #000B20
+ #EBF0FF
+ #000000
+ #BAC3D8
+ #030B1A
+ #FFE9FF
+ #000000
+ #D8B8DC
+ #16041D
+ #FFECE9
+ #000000
+ #FFAEA4
+ #220001
+ #111318
+ #E2E2E9
+ #111318
+ #FFFFFF
+ #44474E
+ #FFFFFF
+ #EEEFF9
+ #C0C2CC
+ #000000
+ #E2E2E9
+ #000000
+ #294878
+ #D6E3FF
+ #000000
+ #AAC7FF
+ #00112B
+ #DAE2F9
+ #000000
+ #BEC6DC
+ #081121
+ #FAD8FD
+ #000000
+ #DDBCE0
+ #1D0823
+ #111318
+ #4E5056
+ #000000
+ #1D2024
+ #2E3036
+ #393B41
+ #45474C
+
diff --git a/app/src/main/res/values-night/styles.xml b/app/src/main/res/values-night/styles.xml
deleted file mode 100644
index 8d47687a..00000000
--- a/app/src/main/res/values-night/styles.xml
+++ /dev/null
@@ -1,33 +0,0 @@
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/app/src/main/res/values-night/theme_overlays.xml b/app/src/main/res/values-night/theme_overlays.xml
new file mode 100644
index 00000000..d0ad798a
--- /dev/null
+++ b/app/src/main/res/values-night/theme_overlays.xml
@@ -0,0 +1,153 @@
+
+
+
+
+
+
+
+
diff --git a/app/src/main/res/values-night/themes.xml b/app/src/main/res/values-night/themes.xml
new file mode 100644
index 00000000..be8186ca
--- /dev/null
+++ b/app/src/main/res/values-night/themes.xml
@@ -0,0 +1,75 @@
+
+
+
+
+
+
diff --git a/app/src/main/res/values/colors.xml b/app/src/main/res/values/colors.xml
index a63ca599..80722bbd 100644
--- a/app/src/main/res/values/colors.xml
+++ b/app/src/main/res/values/colors.xml
@@ -24,12 +24,146 @@
- #3F51B5
- #303F9F
- #EC407A
-
- @color/indigo_500
- @color/indigo_700
- @color/pink_400
+ #415F91
+ #FFFFFF
+ #D6E3FF
+ #284777
+ #565F71
+ #FFFFFF
+ #DAE2F9
+ #3E4759
+ #705575
+ #FFFFFF
+ #FAD8FD
+ #573E5C
+ #BA1A1A
+ #FFFFFF
+ #FFDAD6
+ #93000A
+ #F9F9FF
+ #191C20
+ #F9F9FF
+ #191C20
+ #E0E2EC
+ #44474E
+ #74777F
+ #C4C6D0
+ #000000
+ #2E3036
+ #F0F0F7
+ #AAC7FF
+ #D6E3FF
+ #001B3E
+ #AAC7FF
+ #284777
+ #DAE2F9
+ #131C2B
+ #BEC6DC
+ #3E4759
+ #FAD8FD
+ #28132E
+ #DDBCE0
+ #573E5C
+ #D9D9E0
+ #F9F9FF
+ #FFFFFF
+ #F3F3FA
+ #EDEDF4
+ #E7E8EE
+ #E2E2E9
+ #133665
+ #FFFFFF
+ #506DA0
+ #FFFFFF
+ #2E3647
+ #FFFFFF
+ #646D80
+ #FFFFFF
+ #452E4A
+ #FFFFFF
+ #7F6484
+ #FFFFFF
+ #740006
+ #FFFFFF
+ #CF2C27
+ #FFFFFF
+ #F9F9FF
+ #191C20
+ #F9F9FF
+ #0F1116
+ #E0E2EC
+ #33363E
+ #4F525A
+ #6A6D75
+ #000000
+ #2E3036
+ #F0F0F7
+ #AAC7FF
+ #506DA0
+ #FFFFFF
+ #375586
+ #FFFFFF
+ #646D80
+ #FFFFFF
+ #4C5567
+ #FFFFFF
+ #7F6484
+ #FFFFFF
+ #654C6B
+ #FFFFFF
+ #C5C6CD
+ #F9F9FF
+ #FFFFFF
+ #F3F3FA
+ #E7E8EE
+ #DCDCE3
+ #D1D1D8
+ #032B5B
+ #FFFFFF
+ #2A497A
+ #FFFFFF
+ #232C3D
+ #FFFFFF
+ #41495B
+ #FFFFFF
+ #3A2440
+ #FFFFFF
+ #59405E
+ #FFFFFF
+ #600004
+ #FFFFFF
+ #98000A
+ #FFFFFF
+ #F9F9FF
+ #191C20
+ #F9F9FF
+ #000000
+ #E0E2EC
+ #000000
+ #292C33
+ #464951
+ #000000
+ #2E3036
+ #FFFFFF
+ #AAC7FF
+ #2A497A
+ #FFFFFF
+ #0E3262
+ #FFFFFF
+ #41495B
+ #FFFFFF
+ #2A3344
+ #FFFFFF
+ #59405E
+ #FFFFFF
+ #412A47
+ #FFFFFF
+ #B8B8BF
+ #F9F9FF
+ #FFFFFF
+ #F0F0F7
+ #E2E2E9
+ #D3D4DB
+ #C5C6CD
\ No newline at end of file
diff --git a/app/src/main/res/values/styles.xml b/app/src/main/res/values/styles.xml
deleted file mode 100644
index 47687e19..00000000
--- a/app/src/main/res/values/styles.xml
+++ /dev/null
@@ -1,38 +0,0 @@
-
-
-
-
-
-
-
-
-
diff --git a/app/src/main/res/values/theme_overlays.xml b/app/src/main/res/values/theme_overlays.xml
new file mode 100644
index 00000000..f45f55f1
--- /dev/null
+++ b/app/src/main/res/values/theme_overlays.xml
@@ -0,0 +1,153 @@
+
+
+
+
+
+
+
+
diff --git a/app/src/main/res/values/themes.xml b/app/src/main/res/values/themes.xml
new file mode 100644
index 00000000..c3b429a2
--- /dev/null
+++ b/app/src/main/res/values/themes.xml
@@ -0,0 +1,75 @@
+
+
+
+
+
+
From 56e7166c77c706b4474a279a7f0a286b4dcad965 Mon Sep 17 00:00:00 2001
From: Rosemoe <2073412493@qq.com>
Date: Mon, 9 Feb 2026 12:09:39 +0800
Subject: [PATCH 11/43] fix(editor): non-null param is declared nullable in
`SpanExternalRenderer`
---
.../rosemoe/sora/lang/styling/span/SpanExternalRenderer.kt | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/editor/src/main/java/io/github/rosemoe/sora/lang/styling/span/SpanExternalRenderer.kt b/editor/src/main/java/io/github/rosemoe/sora/lang/styling/span/SpanExternalRenderer.kt
index a880e000..e448732d 100644
--- a/editor/src/main/java/io/github/rosemoe/sora/lang/styling/span/SpanExternalRenderer.kt
+++ b/editor/src/main/java/io/github/rosemoe/sora/lang/styling/span/SpanExternalRenderer.kt
@@ -64,7 +64,7 @@ interface SpanExternalRenderer : SpanExt {
* @param canvas The canvas to draw
* @param paint Paint for measuring
* @param colorScheme Current color scheme
- * @param preOrPost True for preDraw, False for postDraw
+ * @param preOrPost `true` for preDraw, `false` for postDraw
*/
- fun draw(canvas: Canvas?, paint: Paint?, colorScheme: EditorColorScheme?, preOrPost: Boolean)
+ fun draw(canvas: Canvas, paint: Paint, colorScheme: EditorColorScheme, preOrPost: Boolean)
}
\ No newline at end of file
From 77c8ab788292aa2f10e7f72ea904d4744cab1763 Mon Sep 17 00:00:00 2001
From: Rosemoe <2073412493@qq.com>
Date: Mon, 9 Feb 2026 21:03:40 +0800
Subject: [PATCH 12/43] fix(editor): text style in line info panel can be
affected by content text
---
.../main/java/io/github/rosemoe/sora/widget/EditorRenderer.java | 2 ++
1 file changed, 2 insertions(+)
diff --git a/editor/src/main/java/io/github/rosemoe/sora/widget/EditorRenderer.java b/editor/src/main/java/io/github/rosemoe/sora/widget/EditorRenderer.java
index 3bd08662..966426e7 100644
--- a/editor/src/main/java/io/github/rosemoe/sora/widget/EditorRenderer.java
+++ b/editor/src/main/java/io/github/rosemoe/sora/widget/EditorRenderer.java
@@ -2134,6 +2134,8 @@ protected void drawLineInfoPanel(Canvas canvas, float topY, float length) {
int position = editor.getLnPanelPosition();
String text = editor.getLineNumberTipTextProvider().getCurrentText(editor);
float backupSize = paintGeneral.getTextSize();
+ paintGeneral.setTextSkewX(0f);
+ paintGeneral.setFakeBoldText(false);
paintGeneral.setTextSize(editor.getLineInfoTextSize());
Paint.FontMetricsInt backupMetrics = metricsText;
metricsText = paintGeneral.getFontMetricsInt();
From 795f2f0b2bdb92dfd0b512fba3b02fc3b846f558 Mon Sep 17 00:00:00 2001
From: Rosemoe <2073412493@qq.com>
Date: Mon, 9 Feb 2026 21:04:12 +0800
Subject: [PATCH 13/43] fix(app): inconsistent inlay hint position in demo
---
.../main/java/io/github/rosemoe/sora/app/MainActivity.kt | 7 +++----
1 file changed, 3 insertions(+), 4 deletions(-)
diff --git a/app/src/main/java/io/github/rosemoe/sora/app/MainActivity.kt b/app/src/main/java/io/github/rosemoe/sora/app/MainActivity.kt
index 6ecdbfa1..42280fa5 100644
--- a/app/src/main/java/io/github/rosemoe/sora/app/MainActivity.kt
+++ b/app/src/main/java/io/github/rosemoe/sora/app/MainActivity.kt
@@ -588,10 +588,9 @@ class MainActivity : AppCompatActivity() {
if ("big_sample" !in name) {
binding.editor.inlayHints = InlayHintsContainer().also {
- it.add(TextInlayHint(28, 0, "unit:"))
- it.add(TextInlayHint(28, 7, "open"))
- it.add(TextInlayHint(28, 22, "^class"))
- it.add(ColorInlayHint(30, 30, ConstColor("#f44336")))
+ it.add(ColorInlayHint(10, 30, ConstColor("#f44336")))
+ it.add(TextInlayHint(29, 7, "^DigitTens"))
+ it.add(TextInlayHint(100, 1, "^Numbers"))
}
}
}
From 1bf35488e6a708dbd4a813d13f41d94935ed655a Mon Sep 17 00:00:00 2001
From: Rosemoe <2073412493@qq.com>
Date: Mon, 9 Feb 2026 21:09:03 +0800
Subject: [PATCH 14/43] docs: update screenshots in project README
---
README.es.md | 2 +-
README.jp.md | 2 +-
README.md | 2 +-
README.zh-cn.md | 2 +-
images/auto_completion.jpg | Bin 0 -> 662182 bytes
images/general.jpg | Bin 544564 -> 695921 bytes
images/problem_indicators.jpg | Bin 570374 -> 0 bytes
7 files changed, 4 insertions(+), 4 deletions(-)
create mode 100644 images/auto_completion.jpg
delete mode 100644 images/problem_indicators.jpg
diff --git a/README.es.md b/README.es.md
index 75e15856..55ffd804 100644
--- a/README.es.md
+++ b/README.es.md
@@ -54,7 +54,7 @@ Consulte las [combinaciones de teclas admitidas](./keybindings.md).
## Para empezar
diff --git a/README.jp.md b/README.jp.md
index 0b849c7e..e0dc09e4 100644
--- a/README.jp.md
+++ b/README.jp.md
@@ -51,7 +51,7 @@ sora-editor は効率的な Android コードエディターです
## 始めに
diff --git a/README.md b/README.md
index 2ec92b73..95a627aa 100644
--- a/README.md
+++ b/README.md
@@ -54,7 +54,7 @@ visit [Documentation Site](https://project-sora.github.io/sora-editor-docs/).
## Discuss
diff --git a/README.zh-cn.md b/README.zh-cn.md
index ae434f10..b315570a 100644
--- a/README.zh-cn.md
+++ b/README.zh-cn.md
@@ -48,7 +48,7 @@ sora-editor是一款高效的安卓代码编辑器
## 讨论
diff --git a/images/auto_completion.jpg b/images/auto_completion.jpg
new file mode 100644
index 0000000000000000000000000000000000000000..66d5edc9db5bd8141bc31d187675d5cece605c35
GIT binary patch
literal 662182
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