Try fixing index OOB issues in Editable.checkSuggestionNeeded (#6303)
- Fix the case where the order for `start` and `end` is reversed. - Fix the case where `start` or `end` may be outside the editable's range (`0..length`).
This commit is contained in:
parent
18e5b47106
commit
28c9bed632
1 changed files with 21 additions and 3 deletions
|
|
@ -42,6 +42,7 @@ import io.element.android.libraries.textcomposer.model.SuggestionType
|
||||||
import io.element.android.libraries.textcomposer.model.aMarkdownTextEditorState
|
import io.element.android.libraries.textcomposer.model.aMarkdownTextEditorState
|
||||||
import io.element.android.wysiwyg.compose.RichTextEditorStyle
|
import io.element.android.wysiwyg.compose.RichTextEditorStyle
|
||||||
import io.element.android.wysiwyg.compose.internal.applyStyleInCompose
|
import io.element.android.wysiwyg.compose.internal.applyStyleInCompose
|
||||||
|
import timber.log.Timber
|
||||||
|
|
||||||
@Suppress("ModifierMissing")
|
@Suppress("ModifierMissing")
|
||||||
@Composable
|
@Composable
|
||||||
|
|
@ -149,8 +150,20 @@ fun MarkdownTextInput(
|
||||||
|
|
||||||
private fun Editable.checkSuggestionNeeded(): Suggestion? {
|
private fun Editable.checkSuggestionNeeded(): Suggestion? {
|
||||||
if (this.isEmpty()) return null
|
if (this.isEmpty()) return null
|
||||||
val start = Selection.getSelectionStart(this)
|
var start = Selection.getSelectionStart(this)
|
||||||
val end = Selection.getSelectionEnd(this)
|
var end = Selection.getSelectionEnd(this)
|
||||||
|
val range = 0..this.length
|
||||||
|
|
||||||
|
if (start !in range || end !in range) {
|
||||||
|
Timber.tag("checkSuggestionNeeded").e("Selection indices are out of bounds: start=$start, end=$end, text length=${this.length}")
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
// Make sure the selection order is correct, if not swap them: sometimes we can get the end before the start
|
||||||
|
val tempEnd = end
|
||||||
|
end = maxOf(start, end)
|
||||||
|
start = minOf(start, tempEnd)
|
||||||
|
|
||||||
var startOfWord = start
|
var startOfWord = start
|
||||||
while ((startOfWord > 0 || startOfWord == length) && !this[startOfWord - 1].isWhitespace()) {
|
while ((startOfWord > 0 || startOfWord == length) && !this[startOfWord - 1].isWhitespace()) {
|
||||||
startOfWord--
|
startOfWord--
|
||||||
|
|
@ -161,11 +174,16 @@ private fun Editable.checkSuggestionNeeded(): Suggestion? {
|
||||||
// If a mention span already exists we don't need suggestions
|
// If a mention span already exists we don't need suggestions
|
||||||
if (getSpans<MentionSpan>(startOfWord, startOfWord + 1).isNotEmpty()) return null
|
if (getSpans<MentionSpan>(startOfWord, startOfWord + 1).isNotEmpty()) return null
|
||||||
|
|
||||||
return if (firstChar in listOf('@', '#', '/')) {
|
return if (firstChar in listOf('@', '#', '/', ':')) {
|
||||||
var endOfWord = end
|
var endOfWord = end
|
||||||
while (endOfWord < this.length && !this[endOfWord].isWhitespace()) {
|
while (endOfWord < this.length && !this[endOfWord].isWhitespace()) {
|
||||||
endOfWord++
|
endOfWord++
|
||||||
}
|
}
|
||||||
|
if (startOfWord + 1 > endOfWord) {
|
||||||
|
Timber.tag("checkSuggestionNeeded").e("No need to show suggestions for an invalid range (${startOfWord + 1}..$endOfWord)")
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
val text = this.subSequence(startOfWord + 1, endOfWord).toString()
|
val text = this.subSequence(startOfWord + 1, endOfWord).toString()
|
||||||
val suggestionType = when (firstChar) {
|
val suggestionType = when (firstChar) {
|
||||||
'@' -> SuggestionType.Mention
|
'@' -> SuggestionType.Mention
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue