mirror of
https://github.com/ichmagmaus111/ghostgram.git
synced 2026-11-03 14:17:19 +01:00
Ghostgram for iOS, rebuilt from scratch on Telegram iOS 13.0. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
133 lines
3.9 KiB
Swift
133 lines
3.9 KiB
Swift
import Foundation
|
|
import Postbox
|
|
import TelegramCore
|
|
|
|
struct ResolvedEphemeralBotCommand {
|
|
let botPeerId: PeerId
|
|
let text: String
|
|
let entities: [MessageTextEntity]
|
|
}
|
|
|
|
private struct ParsedBotCommandToken {
|
|
let command: String
|
|
let botAddressName: String?
|
|
let length: Int
|
|
}
|
|
|
|
private func isBotCommandScalar(_ scalar: UnicodeScalar) -> Bool {
|
|
if scalar.value >= 48 && scalar.value <= 57 {
|
|
return true
|
|
}
|
|
if scalar.value >= 65 && scalar.value <= 90 {
|
|
return true
|
|
}
|
|
if scalar.value >= 97 && scalar.value <= 122 {
|
|
return true
|
|
}
|
|
return scalar.value == 95
|
|
}
|
|
|
|
private func parseFirstBotCommandToken(_ text: String) -> ParsedBotCommandToken? {
|
|
let nsText = text as NSString
|
|
if nsText.length < 2 || nsText.character(at: 0) != 47 {
|
|
return nil
|
|
}
|
|
|
|
var index = 1
|
|
while index < nsText.length {
|
|
let value = nsText.character(at: index)
|
|
guard let scalar = UnicodeScalar(Int(value)), isBotCommandScalar(scalar) else {
|
|
break
|
|
}
|
|
index += 1
|
|
}
|
|
|
|
if index == 1 {
|
|
return nil
|
|
}
|
|
|
|
let command = nsText.substring(with: NSRange(location: 1, length: index - 1))
|
|
var botAddressName: String?
|
|
|
|
if index < nsText.length && nsText.character(at: index) == 64 {
|
|
let botStartIndex = index + 1
|
|
index = botStartIndex
|
|
while index < nsText.length {
|
|
let value = nsText.character(at: index)
|
|
guard let scalar = UnicodeScalar(Int(value)), isBotCommandScalar(scalar) else {
|
|
break
|
|
}
|
|
index += 1
|
|
}
|
|
if index == botStartIndex {
|
|
return nil
|
|
}
|
|
botAddressName = nsText.substring(with: NSRange(location: botStartIndex, length: index - botStartIndex))
|
|
}
|
|
|
|
if index < nsText.length {
|
|
let value = nsText.character(at: index)
|
|
guard let scalar = UnicodeScalar(Int(value)), CharacterSet.whitespacesAndNewlines.contains(scalar) else {
|
|
return nil
|
|
}
|
|
}
|
|
|
|
return ParsedBotCommandToken(command: command, botAddressName: botAddressName, length: index)
|
|
}
|
|
|
|
func mayContainTypedEphemeralBotCommand(_ text: String) -> Bool {
|
|
return parseFirstBotCommandToken(text) != nil
|
|
}
|
|
|
|
func resolveEphemeralBotCommand(text: String, peerCommands: PeerCommands, forcedBotPeerId: PeerId? = nil) -> ResolvedEphemeralBotCommand? {
|
|
guard let parsed = parseFirstBotCommandToken(text) else {
|
|
return nil
|
|
}
|
|
|
|
var matches = peerCommands.commands.filter { command in
|
|
if command.command.text != parsed.command {
|
|
return false
|
|
}
|
|
if let forcedBotPeerId, command.peer.id != forcedBotPeerId {
|
|
return false
|
|
}
|
|
if let botAddressName = parsed.botAddressName {
|
|
guard let addressName = command.peer.addressName else {
|
|
return false
|
|
}
|
|
return addressName.caseInsensitiveCompare(botAddressName) == .orderedSame
|
|
}
|
|
return true
|
|
}
|
|
|
|
if forcedBotPeerId == nil && parsed.botAddressName == nil && matches.count != 1 {
|
|
return nil
|
|
}
|
|
|
|
if forcedBotPeerId != nil {
|
|
matches = Array(matches.prefix(1))
|
|
}
|
|
|
|
guard let match = matches.first, match.command.isEphemeral else {
|
|
return nil
|
|
}
|
|
|
|
let resolvedText: String
|
|
let commandLength: Int
|
|
if parsed.botAddressName == nil, let addressName = match.peer.addressName, !addressName.isEmpty {
|
|
let commandText = "/\(parsed.command)@\(addressName)"
|
|
let suffix = (text as NSString).substring(from: parsed.length)
|
|
resolvedText = commandText + suffix
|
|
commandLength = (commandText as NSString).length
|
|
} else {
|
|
resolvedText = text
|
|
commandLength = parsed.length
|
|
}
|
|
|
|
return ResolvedEphemeralBotCommand(
|
|
botPeerId: match.peer.id,
|
|
text: resolvedText,
|
|
entities: [MessageTextEntity(range: 0 ..< commandLength, type: .BotCommand)]
|
|
)
|
|
}
|