1
0
mirror of https://github.com/InsanusMokrassar/TelegramBotAPI.git synced 2024-06-03 00:15:27 +00:00
tgbotapi/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/MessageEntity/RawMessageEntity.kt

194 lines
7.5 KiB
Kotlin
Raw Normal View History

2020-10-04 11:06:30 +00:00
package dev.inmo.tgbotapi.types.MessageEntity
2018-12-26 08:07:24 +00:00
2020-10-04 11:06:30 +00:00
import dev.inmo.tgbotapi.types.MessageEntity.textsources.*
import dev.inmo.tgbotapi.types.User
2019-04-13 02:21:19 +00:00
import kotlinx.serialization.Serializable
2018-12-26 08:07:24 +00:00
@Serializable
2019-08-17 16:48:18 +00:00
internal data class RawMessageEntity(
2018-12-26 08:07:24 +00:00
val type: String,
val offset: Int,
val length: Int,
val url: String? = null,
2020-01-23 11:07:28 +00:00
val user: User? = null,
val language: String? = null
2021-04-28 13:54:57 +00:00
) {
internal val range by lazy {
offset until (offset + length)
}
}
2021-04-28 13:54:57 +00:00
internal fun RawMessageEntity.asTextSource(
2020-11-06 08:37:13 +00:00
source: String,
2021-05-29 09:34:14 +00:00
subParts: TextSourcesList
): TextSource {
2021-04-28 13:54:57 +00:00
val sourceSubstring: String = source.substring(range)
val subPartsWithRegulars by lazy {
subParts.fillWithRegulars(sourceSubstring)
}
return when (type) {
2021-04-28 13:54:57 +00:00
"mention" -> MentionTextSource(sourceSubstring, subPartsWithRegulars)
"hashtag" -> HashTagTextSource(sourceSubstring, subPartsWithRegulars)
"cashtag" -> CashTagTextSource(sourceSubstring, subPartsWithRegulars)
2020-11-06 12:52:59 +00:00
"bot_command" -> BotCommandTextSource(sourceSubstring)
"url" -> URLTextSource(sourceSubstring)
2021-04-28 13:54:57 +00:00
"email" -> EMailTextSource(sourceSubstring, subPartsWithRegulars)
"phone_number" -> PhoneNumberTextSource(sourceSubstring, subPartsWithRegulars)
"bold" -> BoldTextSource(sourceSubstring, subPartsWithRegulars)
"italic" -> ItalicTextSource(sourceSubstring, subPartsWithRegulars)
"code" -> CodeTextSource(sourceSubstring)
2020-01-23 11:07:28 +00:00
"pre" -> PreTextSource(sourceSubstring, language)
"text_link" -> TextLinkTextSource(
sourceSubstring,
url ?: throw IllegalStateException("URL must not be null for text link")
)
"text_mention" -> TextMentionTextSource(
sourceSubstring,
user ?: throw IllegalStateException("User must not be null for text mention"),
subPartsWithRegulars
)
2021-04-28 13:54:57 +00:00
"underline" -> UnderlineTextSource(sourceSubstring, subPartsWithRegulars)
"strikethrough" -> StrikethroughTextSource(sourceSubstring, subPartsWithRegulars)
2021-12-31 07:48:51 +00:00
"spoiler" -> SpoilerTextSource(sourceSubstring, subPartsWithRegulars)
else -> RegularTextSource(sourceSubstring)
2021-04-28 13:54:57 +00:00
}
}
private inline operator fun <T : Comparable<T>> ClosedRange<T>.contains(other: ClosedRange<T>): Boolean {
return start <= other.start && endInclusive >= other.endInclusive
}
2021-05-29 09:34:14 +00:00
internal fun TextSourcesList.fillWithRegulars(source: String): TextSourcesList {
2021-04-28 13:54:57 +00:00
var index = 0
2021-05-29 09:34:14 +00:00
val result = mutableListOf<TextSource>()
2021-04-28 13:54:57 +00:00
for (i in 0 until size) {
val textSource = get(i)
val thisSourceInStart = source.startsWith(textSource.source, index)
if (!thisSourceInStart) {
2021-05-05 13:02:22 +00:00
val regularEndIndex = source.indexOf(textSource.source, index)
2021-04-28 13:54:57 +00:00
result.add(regular(source.substring(index, regularEndIndex)))
index = regularEndIndex
2018-12-26 08:07:24 +00:00
}
2021-04-28 13:54:57 +00:00
result.add(textSource)
index += textSource.source.length
2018-12-26 08:07:24 +00:00
}
2021-04-28 13:54:57 +00:00
if (index != source.length) {
result.add(regular(source.substring(index, source.length)))
}
return result
2018-12-26 08:07:24 +00:00
}
private fun createTextSources(
originalFullString: String,
entities: RawMessageEntities
2021-05-29 09:34:14 +00:00
): TextSourcesList {
2021-04-28 13:54:57 +00:00
val mutableEntities = entities.toMutableList().apply { sortBy { it.offset } }
2021-05-29 09:34:14 +00:00
val resultList = mutableListOf<TextSource>()
2018-12-26 08:07:24 +00:00
while (mutableEntities.isNotEmpty()) {
2021-04-28 13:54:57 +00:00
var parent = mutableEntities.removeFirst()
val subentities = mutableListOf<RawMessageEntity>()
val toAddCutted = mutableListOf<RawMessageEntity>()
while (mutableEntities.isNotEmpty()) {
val potentialParent = mutableEntities.first()
when {
potentialParent.range.first > parent.range.last -> break
potentialParent.range in parent.range -> {
subentities.add(potentialParent)
}
potentialParent.offset == parent.offset && potentialParent.length > parent.length -> {
subentities.add(parent)
parent = potentialParent
}
else -> { // need to cut
toAddCutted.add(potentialParent)
}
}
2021-04-28 13:54:57 +00:00
mutableEntities.remove(potentialParent)
}
val subtextSources = if (subentities.isNotEmpty()) {
mutableEntities.removeAll(subentities)
if (toAddCutted.isNotEmpty()) {
val borderIndex = parent.range.last + 1
mutableEntities.addAll(
0,
toAddCutted.map {
val firstLength = borderIndex - it.offset
subentities.add(it.copy(length = firstLength))
it.copy(
offset = borderIndex,
length = it.length - firstLength
)
}
)
}
createTextSources(originalFullString, subentities)
} else {
2021-04-28 13:54:57 +00:00
emptyList()
}
2021-04-28 13:54:57 +00:00
resultList.add(
parent.asTextSource(
2020-11-06 08:37:13 +00:00
originalFullString,
2021-04-28 13:54:57 +00:00
subtextSources
)
)
}
return resultList
}
2021-05-29 09:34:14 +00:00
internal fun TextSource.toRawMessageEntities(offset: Int = 0): List<RawMessageEntity> {
2020-11-06 08:37:13 +00:00
val source = source
2021-04-28 13:54:57 +00:00
val length = source.length
2020-11-06 08:37:13 +00:00
return listOfNotNull(
2021-04-28 13:54:57 +00:00
when (this) {
is MentionTextSource -> RawMessageEntity("mention", offset, length)
is HashTagTextSource -> RawMessageEntity("hashtag", offset, length)
is CashTagTextSource -> RawMessageEntity("cashtag", offset, length)
is BotCommandTextSource -> RawMessageEntity("bot_command", offset, length)
is URLTextSource -> RawMessageEntity("url", offset, length)
is EMailTextSource -> RawMessageEntity("email", offset, length)
is PhoneNumberTextSource -> RawMessageEntity("phone_number", offset, length)
is BoldTextSource -> RawMessageEntity("bold", offset, length)
is ItalicTextSource -> RawMessageEntity("italic", offset, length)
is CodeTextSource -> RawMessageEntity("code", offset, length)
is PreTextSource -> RawMessageEntity("pre", offset, length, language = language)
is TextLinkTextSource -> RawMessageEntity("text_link", offset, length, url)
is TextMentionTextSource -> RawMessageEntity("text_mention", offset, length, user = user)
is UnderlineTextSource -> RawMessageEntity("underline", offset, length)
is StrikethroughTextSource -> RawMessageEntity("strikethrough", offset, length)
2021-12-31 07:48:51 +00:00
is SpoilerTextSource -> RawMessageEntity("spoiler", offset, length)
2020-11-06 08:37:13 +00:00
else -> null
}
2021-04-28 13:54:57 +00:00
) + if (this is MultilevelTextSource) {
subsources.toRawMessageEntities(offset)
2020-11-06 08:37:13 +00:00
} else {
emptyList()
}
}
2020-11-06 08:37:13 +00:00
2021-05-29 09:34:14 +00:00
internal fun TextSourcesList.toRawMessageEntities(preOffset: Int = 0): List<RawMessageEntity> {
2020-11-06 08:37:13 +00:00
var i = preOffset
2021-04-28 17:22:13 +00:00
return flatMap { textSource ->
textSource.toRawMessageEntities(i).also {
i += it.maxByOrNull { it.length }?.length ?: textSource.source.length
}
2020-11-06 08:37:13 +00:00
}
}
fun String.removeLeading(word: String) = if (startsWith(word)) {
2020-11-06 12:52:59 +00:00
substring(word.length)
} else {
this
}
2021-05-29 09:34:14 +00:00
internal fun TextSourcesList.toRawMessageEntities(): List<RawMessageEntity> = toRawMessageEntities(0)
2020-11-06 08:37:13 +00:00
2021-05-29 09:34:14 +00:00
internal fun RawMessageEntities.asTextSources(sourceString: String): TextSourcesList =
createTextSources(sourceString, this).fillWithRegulars(sourceString)
internal typealias RawMessageEntities = List<RawMessageEntity>