Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
9beb856
chore(deps): update styfle/cancel-workflow-action action to v0.13.0
renovate[bot] Jan 15, 2026
0bb9c1b
Merge pull request #788 from Rosemoe/renovate/styfle-cancel-workflow-…
Rosemoe Jan 17, 2026
9e6b8d8
chore(build): remove kotlin plugin from version catalog
Rosemoe Jan 18, 2026
787c000
build(oniguruma): exclude test code in compilation
Rosemoe Jan 18, 2026
f2f5301
fix(build): build-logic has no task named `clean`, preventing IDE `Cl…
Rosemoe Jan 18, 2026
3785770
feat(editor): add click event for inlay hints
Rosemoe Jan 18, 2026
1a7cf4b
chore(deps): downgrade kotlin to v2.2.x
Rosemoe Jan 18, 2026
494b930
feat(editor): implement simple preserve-case replacing (close #792)
Rosemoe Jan 19, 2026
fb6a4c8
fix(editor): UI update from LSP on non-main thread (#793)
mucute-qwq Jan 22, 2026
cc5448d
fix(editor): wordwrap forces to break after a trailing period
Rosemoe Jan 22, 2026
82fdbbb
feat(editor): add border color customization for built-in color inlay…
Rosemoe Jan 23, 2026
c140119
feat(editor): move auto completion description to the right, add supp…
KonerDev Jan 23, 2026
460789d
feat(editor-lsp): add support for detail text and deprecation
KonerDev Jan 23, 2026
4aa37ef
chore: replace `.gitmodules` SSH with HTTPS URL
KonerDev Jan 23, 2026
ab711e6
fix(editor-lsp): fix copy button overlapping with container message
KonerDev Jan 23, 2026
37b1c0e
chore: revert `.gitmodules` URL from HTTPS to SSH
KonerDev Jan 24, 2026
a8b9864
feat: implement color span drawable, extract color in LSP completion …
KonerDev Jan 24, 2026
0ebab4a
feat: implement registerable file/folder icons for completion items
KonerDev Jan 24, 2026
60c3719
feat: support various color formats (RGB, HSL, HEX), show color value…
KonerDev Jan 24, 2026
ea8fc1d
feat: decrease icon size of completion item
KonerDev Jan 24, 2026
ccb4888
feat: make default secondary completion text color less prominent
KonerDev Jan 24, 2026
66f4ae0
chore: remove unused variable
KonerDev Jan 24, 2026
3629c6e
feat(editor): enlarge padding to increase touch size
KonerDev Jan 24, 2026
5fb34ae
Merge pull request #795 from KonerDev/feat/auto-completion
Rosemoe Jan 25, 2026
e90ec9e
Merge upstream
KonerDev Jan 25, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/gradle.yml
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Cancel Previous Runs
uses: styfle/cancel-workflow-action@0.12.1
uses: styfle/cancel-workflow-action@0.13.0
with:
access_token: ${{ github.token }}

Expand Down
7 changes: 7 additions & 0 deletions app/src/main/java/io/github/rosemoe/sora/app/MainActivity.kt
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ import io.github.rosemoe.sora.app.lsp.LspTestJavaActivity
import io.github.rosemoe.sora.app.tests.TestActivity
import io.github.rosemoe.sora.event.ContentChangeEvent
import io.github.rosemoe.sora.event.EditorKeyEvent
import io.github.rosemoe.sora.event.InlayHintClickEvent
import io.github.rosemoe.sora.event.KeyBindingEvent
import io.github.rosemoe.sora.event.PublishSearchResultEvent
import io.github.rosemoe.sora.event.SelectionChangeEvent
Expand Down Expand Up @@ -91,6 +92,7 @@ import io.github.rosemoe.sora.utils.codePointStringAt
import io.github.rosemoe.sora.utils.escapeCodePointIfNecessary
import io.github.rosemoe.sora.utils.toast
import io.github.rosemoe.sora.widget.CodeEditor
import io.github.rosemoe.sora.widget.EditorSearcher
import io.github.rosemoe.sora.widget.EditorSearcher.SearchOptions
import io.github.rosemoe.sora.widget.SelectionMovement
import io.github.rosemoe.sora.widget.component.EditorAutoCompletion
Expand Down Expand Up @@ -240,6 +242,9 @@ class MainActivity : AppCompatActivity() {
subscribeAlways<SideIconClickEvent> {
toast(R.string.tip_side_icon)
}
subscribeAlways<InlayHintClickEvent> {
toast(R.string.tip_inlay_hint)
}
subscribeAlways<TextSizeChangeEvent> { event ->
Log.d(
TAG,
Expand All @@ -256,6 +261,7 @@ class MainActivity : AppCompatActivity() {
}
}

searcher.replaceOptions = EditorSearcher.ReplaceOptions(true)
// Handle span interactions
EditorSpanInteractionHandler(this)
getComponent<EditorAutoCompletion>()
Expand Down Expand Up @@ -285,6 +291,7 @@ class MainActivity : AppCompatActivity() {
updateBtnState()

switchThemeIfRequired(this, binding.editor)
computeSearchOptions()
}

/**
Expand Down
1 change: 1 addition & 0 deletions app/src/main/res/values-zh/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,7 @@
<string name="hide_soft_kbd_if_hard_kbd_available">物理键盘连接时隐藏软键盘</string>
<string name="deleting_log_success">日志已删除。</string>
<string name="tip_side_icon">点击了侧边按钮</string>
<string name="tip_inlay_hint">点击了嵌入提示</string>
<string name="dialog_lsp_entry_title">选择LSP活动</string>
<string name="dialog_lsp_entry_msg">是否要打开以Kotlin编写的LSP界面?</string>
<string name="choice_yes">是</string>
Expand Down
1 change: 1 addition & 0 deletions app/src/main/res/values/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,7 @@
<string name="hide_soft_kbd_if_hard_kbd_available">Hide soft kbd if hard kbd available</string>
<string name="deleting_log_success">Log removed.</string>
<string name="tip_side_icon">Side icon clicked.</string>
<string name="tip_inlay_hint">Inlay hint clicked.</string>
<string name="dialog_lsp_entry_title">Select LSP Activity</string>
<string name="dialog_lsp_entry_msg">Do you want to open LspActivity written in Kotlin?</string>
<string name="choice_yes">Yes</string>
Expand Down
27 changes: 27 additions & 0 deletions build-logic/build.gradle.kts
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
/*******************************************************************************
* 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
******************************************************************************/

tasks.register<Delete>("clean").configure {
delete(rootProject.layout.buildDirectory)
}
2 changes: 1 addition & 1 deletion build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ fun Project.configureAndroidAndKotlin() {

extensions.findByType<KotlinAndroidExtension>()?.apply {
compilerOptions {
languageVersion = org.jetbrains.kotlin.gradle.dsl.KotlinVersion.KOTLIN_2_3
languageVersion = org.jetbrains.kotlin.gradle.dsl.KotlinVersion.KOTLIN_2_2
jvmTarget = JvmTarget.JVM_17
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -197,7 +197,7 @@ internal class LspEditorUIDelegate(private val editor: LspEditor) {
val editorInstance = currentEditorRef.get() ?: return

if (highlights.isNullOrEmpty()) {
editorInstance.highlightTexts = null
editorInstance.post { editorInstance.highlightTexts = null }
return
}

Expand Down Expand Up @@ -228,7 +228,7 @@ internal class LspEditorUIDelegate(private val editor: LspEditor) {
)
}

editorInstance.highlightTexts = container
editorInstance.post { editorInstance.highlightTexts = container }
}

fun showInlayHints(inlayHints: List<InlayHint>?) {
Expand Down Expand Up @@ -256,23 +256,23 @@ internal class LspEditorUIDelegate(private val editor: LspEditor) {
val hasDocumentColors = !cachedDocumentColors.isNullOrEmpty()

if (!hasInlayHints && !hasDocumentColors) {
editorInstance.inlayHints = null
editorInstance.post { editorInstance.inlayHints = null }
return
}

val container = InlayHintsContainer()
cachedInlayHints?.inlayHintToDisplay()?.forEach(container::add)
cachedDocumentColors?.colorInfoToDisplay()?.forEach(container::add)

editorInstance.inlayHints = container
editorInstance.post { editorInstance.inlayHints = container }
}

private fun resetInlinePresentations() {
cachedInlayHints = null
cachedDocumentColors = null
currentEditorRef.get()?.let {
if (it.inlayHints != null) {
it.inlayHints = null
it.post { it.inlayHints = null }
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,10 +26,13 @@ package io.github.rosemoe.sora.lsp.editor.completion

import io.github.rosemoe.sora.lang.completion.CompletionItemKind
import io.github.rosemoe.sora.lang.completion.SimpleCompletionIconDrawer.draw
import io.github.rosemoe.sora.lang.completion.SimpleCompletionIconDrawer.drawColorSpan
import io.github.rosemoe.sora.lang.completion.SimpleCompletionIconDrawer.drawFileFolder
import io.github.rosemoe.sora.lang.completion.snippet.parser.CodeSnippetParser
import io.github.rosemoe.sora.lsp.editor.LspEventManager
import io.github.rosemoe.sora.lsp.events.EventType
import io.github.rosemoe.sora.lsp.events.document.applyEdits
import io.github.rosemoe.sora.lsp.utils.ColorUtils
import io.github.rosemoe.sora.lsp.utils.asLspPosition
import io.github.rosemoe.sora.lsp.utils.createPosition
import io.github.rosemoe.sora.lsp.utils.createRange
Expand All @@ -38,10 +41,10 @@ import io.github.rosemoe.sora.text.Content
import io.github.rosemoe.sora.util.Logger
import io.github.rosemoe.sora.widget.CodeEditor
import org.eclipse.lsp4j.CompletionItem
import org.eclipse.lsp4j.CompletionItemTag
import org.eclipse.lsp4j.InsertTextFormat
import org.eclipse.lsp4j.TextEdit


class LspCompletionItem(
private val completionItem: CompletionItem,
private val eventManager: LspEventManager,
Expand All @@ -50,7 +53,6 @@ class LspCompletionItem(
completionItem.label,
completionItem.detail
) {

init {
this.prefixLength = prefixLength
kind =
Expand All @@ -60,10 +62,48 @@ class LspCompletionItem(
sortText = completionItem.sortText
filterText = completionItem.filterText
val labelDetails = completionItem.labelDetails
if (labelDetails != null && labelDetails.description?.isNotEmpty() == true) {
desc = labelDetails.description
if (labelDetails != null) {
if (labelDetails.description?.isNotEmpty() == true) {
desc = labelDetails.description
}
detail = labelDetails.detail
}
val tags = completionItem.tags
if (tags != null) {
deprecated = tags.contains(CompletionItemTag.Deprecated)
}

val fileIcon = when {
kind == CompletionItemKind.File || kind == CompletionItemKind.Folder -> {
label?.let { drawFileFolder(it.toString()) } ?: desc?.let { drawFileFolder(it.toString()) }
}
else -> null
}

icon = fileIcon ?: run {
val colorValue = extractColor()
if (kind == CompletionItemKind.Color && colorValue != null) {
drawColorSpan(colorValue)
} else {
draw(kind ?: CompletionItemKind.Text)
}
}
icon = draw(kind ?: CompletionItemKind.Text)
}

fun extractColor(): Int? {
val labelColor = label?.let { ColorUtils.parseColor(it.toString()) }
val detailColor = desc?.let { ColorUtils.parseColor(it.toString()) }

val documentation = completionItem.documentation?.let {
if (it.isLeft) it.left else it.right.value
}
val documentationColor = documentation?.let { ColorUtils.parseColor(it) }

if (documentationColor != null && detailColor == null && labelColor == null && desc == null) {
desc = documentation
}

return labelColor ?: detailColor ?: documentationColor
}

override fun performCompletion(editor: CodeEditor, text: Content, position: CharPosition) {
Expand All @@ -84,7 +124,10 @@ class LspCompletionItem(
if (completionItem.textEdit != null && completionItem.textEdit.isLeft) {
textEdit = completionItem.textEdit.left
} else if (completionItem.textEdit?.isRight == true) {
textEdit = TextEdit(completionItem.textEdit.right.insert, completionItem.textEdit.right.newText)
textEdit = TextEdit(
completionItem.textEdit.right.insert,
completionItem.textEdit.right.newText
)
}

if (textEdit.newText == null && completionItem.label != null) {
Expand Down Expand Up @@ -164,5 +207,3 @@ class LspCompletionItem(
// do nothing
}
}


Original file line number Diff line number Diff line change
Expand Up @@ -140,4 +140,4 @@ class DocumentColorEvent : AsyncEventListener() {

@get:Experimental
val EventType.documentColor: String
get() = "textDocument/documentColor"
get() = "textDocument/documentColor"
Original file line number Diff line number Diff line change
Expand Up @@ -164,4 +164,4 @@ class InlayHintEvent : AsyncEventListener() {

@get:Experimental
val EventType.inlayHint: String
get() = "textDocument/inlayHint"
get() = "textDocument/inlayHint"
Loading
Loading