diff --git a/app/src/main/java/com/keylesspalace/tusky/util/ComposeTokenizer.kt b/app/src/main/java/com/keylesspalace/tusky/util/ComposeTokenizer.kt index a1294333..c0da4275 100644 --- a/app/src/main/java/com/keylesspalace/tusky/util/ComposeTokenizer.kt +++ b/app/src/main/java/com/keylesspalace/tusky/util/ComposeTokenizer.kt @@ -21,20 +21,52 @@ import android.text.TextUtils import android.widget.MultiAutoCompleteTextView class ComposeTokenizer : MultiAutoCompleteTextView.Tokenizer { + + private fun isMentionOrHashtagAllowedCharacter(character: Char) : Boolean { + return Character.isLetterOrDigit(character) || character == '_' // simple usernames + || character == '-' // extended usernames + || character == '.' // domain dot + } + override fun findTokenStart(text: CharSequence, cursor: Int): Int { if (cursor == 0) { return cursor } var i = cursor var character = text[i - 1] - while (i > 0 && character != '@' && character != '#' && character != ':') { - // See SpanUtils.MENTION_REGEX - if (!Character.isLetterOrDigit(character) && character != '_') { + + // go up to first illegal character or character we're looking for (@, # or :) + while(i > 0 && !(character == '@' || character == '#' || character == ':')) { + if(!isMentionOrHashtagAllowedCharacter(character)) { return cursor } + i-- character = if (i == 0) ' ' else text[i - 1] } + + // maybe caught domain name? try search username + if(i > 2 && character == '@') { + var j = i - 1 + var character2 = text[i - 2] + + // again go up to first illegal character or tag "@" + while(j > 0 && character2 != '@') { + if(!isMentionOrHashtagAllowedCharacter(character2)) { + break + } + + j-- + character2 = if (j == 0) ' ' else text[j - 1] + } + + // found mention symbol, override cursor + if(character2 == '@') { + i = j + character = character2 + } + } + if (i < 1 || (character != '@' && character != '#' && character != ':') || i > 1 && !Character.isWhitespace(text[i - 2])) { diff --git a/app/src/test/java/com/keylesspalace/tusky/ComposeTokenizerTest.kt b/app/src/test/java/com/keylesspalace/tusky/ComposeTokenizerTest.kt index 73a00670..b603a4a7 100644 --- a/app/src/test/java/com/keylesspalace/tusky/ComposeTokenizerTest.kt +++ b/app/src/test/java/com/keylesspalace/tusky/ComposeTokenizerTest.kt @@ -44,6 +44,29 @@ class ComposeTokenizerTest(private val text: CharSequence, arrayOf(" @ment10n_ @ment20n_", 11, 20), arrayOf(" @ment10n_ @ment20n_n", 11, 21), arrayOf(" @ment10n_ @ment20n_9", 11, 21), + arrayOf(" @ment10n-", 1, 10), + arrayOf(" @ment10n- @", 11, 12), + arrayOf(" @ment10n- @ment20n", 11, 19), + arrayOf(" @ment10n- @ment20n-", 11, 20), + arrayOf(" @ment10n- @ment20n-n", 11, 21), + arrayOf(" @ment10n- @ment20n-9", 11, 21), + arrayOf("@ment10n@l0calhost", 0, 18), + arrayOf(" @ment10n@l0calhost", 1, 19), + arrayOf(" @ment10n_@l0calhost", 1, 20), + arrayOf(" @ment10n-@l0calhost", 1, 20), + arrayOf(" @ment10n_@l0calhost @ment20n@husky", 21, 35), + arrayOf(" @ment10n_@l0calhost @ment20n_@husky", 21, 36), + arrayOf(" @ment10n-@l0calhost @ment20n-@husky", 21, 36), + arrayOf(" @m@localhost", 1, 13), + arrayOf(" @m@localhost @a@localhost", 14, 26), + arrayOf("@m@", 0, 3), + arrayOf(" @m@ @a@asdf", 5, 12), + arrayOf(" @m@ @a@", 5, 8), + arrayOf(" @m@ @a@a", 5, 9), + arrayOf(" @m@a @a@m", 6, 10), + arrayOf("@m@m@", 5, 5), + arrayOf("#tusky@husky", 12, 12), + arrayOf(":tusky@husky", 12, 12), arrayOf("mention", 7, 7), arrayOf("ment10n", 7, 7), arrayOf("mentio_", 7, 7),