mirror of
https://github.com/permissionlesstech/bitchat.git
synced 2026-07-25 04:05:20 +00:00
Compare commits
3
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
3e5043f875 | ||
|
|
11cd5527ed | ||
|
|
cf1bfdac6b |
@@ -3043,8 +3043,10 @@ class ChatViewModel: ObservableObject, BitchatDelegate {
|
||||
let mentionRegex = try? NSRegularExpression(pattern: mentionPattern, options: [])
|
||||
let hashtagRegex = try? NSRegularExpression(pattern: hashtagPattern, options: [])
|
||||
|
||||
let mentionMatches = mentionRegex?.matches(in: contentText, options: [], range: NSRange(location: 0, length: contentText.count)) ?? []
|
||||
let hashtagMatches = hashtagRegex?.matches(in: contentText, options: [], range: NSRange(location: 0, length: contentText.count)) ?? []
|
||||
let nsContent = contentText as NSString
|
||||
let nsLen = nsContent.length
|
||||
let mentionMatches = mentionRegex?.matches(in: contentText, options: [], range: NSRange(location: 0, length: nsLen)) ?? []
|
||||
let hashtagMatches = hashtagRegex?.matches(in: contentText, options: [], range: NSRange(location: 0, length: nsLen)) ?? []
|
||||
|
||||
// Combine and sort all matches
|
||||
var allMatches: [(range: NSRange, type: String)] = []
|
||||
@@ -3061,12 +3063,14 @@ class ChatViewModel: ObservableObject, BitchatDelegate {
|
||||
for (matchRange, matchType) in allMatches {
|
||||
// Add text before the match
|
||||
if let range = Range(matchRange, in: contentText) {
|
||||
let beforeText = String(contentText[lastEndIndex..<range.lowerBound])
|
||||
if !beforeText.isEmpty {
|
||||
var normalStyle = AttributeContainer()
|
||||
normalStyle.font = .system(size: 14, design: .monospaced)
|
||||
normalStyle.foregroundColor = isDark ? Color.white : Color.black
|
||||
processedContent.append(AttributedString(beforeText).mergingAttributes(normalStyle))
|
||||
if lastEndIndex < range.lowerBound {
|
||||
let beforeText = String(contentText[lastEndIndex..<range.lowerBound])
|
||||
if !beforeText.isEmpty {
|
||||
var normalStyle = AttributeContainer()
|
||||
normalStyle.font = .system(size: 14, design: .monospaced)
|
||||
normalStyle.foregroundColor = isDark ? Color.white : Color.black
|
||||
processedContent.append(AttributedString(beforeText).mergingAttributes(normalStyle))
|
||||
}
|
||||
}
|
||||
|
||||
// Add the match with appropriate styling
|
||||
@@ -3084,7 +3088,7 @@ class ChatViewModel: ObservableObject, BitchatDelegate {
|
||||
|
||||
processedContent.append(AttributedString(matchText).mergingAttributes(matchStyle))
|
||||
|
||||
lastEndIndex = range.upperBound
|
||||
if lastEndIndex < range.upperBound { lastEndIndex = range.upperBound }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3161,9 +3165,12 @@ class ChatViewModel: ObservableObject, BitchatDelegate {
|
||||
|
||||
// For extremely long content, render as plain text to avoid heavy regex/layout work,
|
||||
// unless the content includes Cashu tokens we want to chip-render below
|
||||
// Compute NSString-backed length for regex/nsrange correctness with multi-byte characters
|
||||
let nsContent = content as NSString
|
||||
let nsLen = nsContent.length
|
||||
let containsCashuEarly: Bool = {
|
||||
let rx = Regexes.quickCashuPresence
|
||||
return rx.numberOfMatches(in: content, options: [], range: NSRange(location: 0, length: content.count)) > 0
|
||||
return rx.numberOfMatches(in: content, options: [], range: NSRange(location: 0, length: nsLen)) > 0
|
||||
}()
|
||||
if (content.count > 4000 || content.hasVeryLongToken(threshold: 1024)) && !containsCashuEarly {
|
||||
var plainStyle = AttributeContainer()
|
||||
@@ -3181,8 +3188,6 @@ class ChatViewModel: ObservableObject, BitchatDelegate {
|
||||
let lnurlRegex = Regexes.lnurl
|
||||
let lightningSchemeRegex = Regexes.lightningScheme
|
||||
let detector = Regexes.linkDetector
|
||||
|
||||
let nsLen = content.count
|
||||
let hasMentionsHint = content.contains("@")
|
||||
let hasHashtagsHint = content.contains("#")
|
||||
let hasURLHint = content.contains("://") || content.contains("www.") || content.contains("http")
|
||||
@@ -3262,17 +3267,19 @@ class ChatViewModel: ObservableObject, BitchatDelegate {
|
||||
for (range, type) in allMatches {
|
||||
// Add text before match
|
||||
if let nsRange = Range(range, in: content) {
|
||||
let beforeText = String(content[lastEnd..<nsRange.lowerBound])
|
||||
if !beforeText.isEmpty {
|
||||
var beforeStyle = AttributeContainer()
|
||||
beforeStyle.foregroundColor = baseColor
|
||||
beforeStyle.font = isSelf
|
||||
? .system(size: 14, weight: .bold, design: .monospaced)
|
||||
: .system(size: 14, design: .monospaced)
|
||||
if isMentioned {
|
||||
beforeStyle.font = beforeStyle.font?.bold()
|
||||
if lastEnd < nsRange.lowerBound {
|
||||
let beforeText = String(content[lastEnd..<nsRange.lowerBound])
|
||||
if !beforeText.isEmpty {
|
||||
var beforeStyle = AttributeContainer()
|
||||
beforeStyle.foregroundColor = baseColor
|
||||
beforeStyle.font = isSelf
|
||||
? .system(size: 14, weight: .bold, design: .monospaced)
|
||||
: .system(size: 14, design: .monospaced)
|
||||
if isMentioned {
|
||||
beforeStyle.font = beforeStyle.font?.bold()
|
||||
}
|
||||
result.append(AttributedString(beforeText).mergingAttributes(beforeStyle))
|
||||
}
|
||||
result.append(AttributedString(beforeText).mergingAttributes(beforeStyle))
|
||||
}
|
||||
|
||||
// Add styled match
|
||||
@@ -3380,7 +3387,10 @@ class ChatViewModel: ObservableObject, BitchatDelegate {
|
||||
result.append(AttributedString(matchText).mergingAttributes(matchStyle))
|
||||
}
|
||||
}
|
||||
lastEnd = nsRange.upperBound
|
||||
// Advance lastEnd safely in case of overlaps
|
||||
if lastEnd < nsRange.upperBound {
|
||||
lastEnd = nsRange.upperBound
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3478,19 +3488,23 @@ class ChatViewModel: ObservableObject, BitchatDelegate {
|
||||
// Regular expression to find @mentions
|
||||
let pattern = "@([\\p{L}0-9_]+)"
|
||||
let regex = try? NSRegularExpression(pattern: pattern, options: [])
|
||||
let matches = regex?.matches(in: contentText, options: [], range: NSRange(location: 0, length: contentText.count)) ?? []
|
||||
let nsContent = contentText as NSString
|
||||
let nsLen = nsContent.length
|
||||
let matches = regex?.matches(in: contentText, options: [], range: NSRange(location: 0, length: nsLen)) ?? []
|
||||
|
||||
var lastEndIndex = contentText.startIndex
|
||||
|
||||
for match in matches {
|
||||
// Add text before the mention
|
||||
if let range = Range(match.range(at: 0), in: contentText) {
|
||||
let beforeText = String(contentText[lastEndIndex..<range.lowerBound])
|
||||
if !beforeText.isEmpty {
|
||||
var normalStyle = AttributeContainer()
|
||||
normalStyle.font = .system(size: 14, design: .monospaced)
|
||||
normalStyle.foregroundColor = isDark ? Color.white : Color.black
|
||||
processedContent.append(AttributedString(beforeText).mergingAttributes(normalStyle))
|
||||
if lastEndIndex < range.lowerBound {
|
||||
let beforeText = String(contentText[lastEndIndex..<range.lowerBound])
|
||||
if !beforeText.isEmpty {
|
||||
var normalStyle = AttributeContainer()
|
||||
normalStyle.font = .system(size: 14, design: .monospaced)
|
||||
normalStyle.foregroundColor = isDark ? Color.white : Color.black
|
||||
processedContent.append(AttributedString(beforeText).mergingAttributes(normalStyle))
|
||||
}
|
||||
}
|
||||
|
||||
// Add the mention with highlight
|
||||
@@ -3500,7 +3514,7 @@ class ChatViewModel: ObservableObject, BitchatDelegate {
|
||||
mentionStyle.foregroundColor = Color.orange
|
||||
processedContent.append(AttributedString(mentionText).mergingAttributes(mentionStyle))
|
||||
|
||||
lastEndIndex = range.upperBound
|
||||
if lastEndIndex < range.upperBound { lastEndIndex = range.upperBound }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4698,7 +4712,9 @@ class ChatViewModel: ObservableObject, BitchatDelegate {
|
||||
// Allow optional disambiguation suffix '#abcd' for duplicate nicknames
|
||||
let pattern = "@([\\p{L}0-9_]+(?:#[a-fA-F0-9]{4})?)"
|
||||
let regex = try? NSRegularExpression(pattern: pattern, options: [])
|
||||
let matches = regex?.matches(in: content, options: [], range: NSRange(location: 0, length: content.count)) ?? []
|
||||
let nsContent = content as NSString
|
||||
let nsLen = nsContent.length
|
||||
let matches = regex?.matches(in: content, options: [], range: NSRange(location: 0, length: nsLen)) ?? []
|
||||
|
||||
var mentions: [String] = []
|
||||
let peerNicknames = meshService.getPeerNicknames()
|
||||
|
||||
Reference in New Issue
Block a user