mirror of
https://github.com/permissionlesstech/bitchat.git
synced 2026-10-18 07:33:46 +00:00
Merge b8f495d3623d5bbbf6e222d28bf5c0d90dd2bffe into 9b84b361225facd8e623f25d76f889d3dc54a879
This commit is contained in:
commit
cc5b1bbdbf
@ -2,7 +2,7 @@
|
||||
// AutocompleteService.swift
|
||||
// bitchat
|
||||
//
|
||||
// Handles autocomplete suggestions for mentions and commands
|
||||
// Handles autocomplete suggestions for mentions
|
||||
// This is free and unencumbered software released into the public domain.
|
||||
//
|
||||
|
||||
@ -10,49 +10,47 @@ import Foundation
|
||||
|
||||
/// Manages autocomplete functionality for chat
|
||||
final class AutocompleteService {
|
||||
private let mentionRegex = try? NSRegularExpression(pattern: "@([\\p{L}0-9_]*)$", options: [])
|
||||
private typealias Patterns = MessageFormattingEngine.Patterns
|
||||
|
||||
/// Get autocomplete suggestions for current text
|
||||
func getSuggestions(for text: String, peers: [String], cursorPosition: Int) -> (suggestions: [String], range: NSRange?) {
|
||||
let textToPosition = String(text.prefix(cursorPosition))
|
||||
|
||||
// Check for mention autocomplete
|
||||
|
||||
// Mentions only — slash-command suggestions are owned by
|
||||
// `CommandSuggestionsView` / the composer, not this service.
|
||||
if let (mentionSuggestions, mentionRange) = getMentionSuggestions(textToPosition, peers: peers) {
|
||||
return (mentionSuggestions, mentionRange)
|
||||
}
|
||||
|
||||
// Don't handle command autocomplete here - ContentView handles it with better UI
|
||||
// if let (commandSuggestions, commandRange) = getCommandSuggestions(textToPosition) {
|
||||
// return (commandSuggestions, commandRange)
|
||||
// }
|
||||
|
||||
|
||||
return ([], nil)
|
||||
}
|
||||
|
||||
|
||||
/// Apply selected suggestion to text
|
||||
func applySuggestion(_ suggestion: String, to text: String, range: NSRange) -> String {
|
||||
guard let textRange = Range(range, in: text) else { return text }
|
||||
|
||||
|
||||
var replacement = suggestion
|
||||
|
||||
|
||||
// Add space after command if it takes arguments
|
||||
if suggestion.hasPrefix("/") && needsArgument(command: suggestion) {
|
||||
replacement += " "
|
||||
}
|
||||
|
||||
|
||||
return text.replacingCharacters(in: textRange, with: replacement)
|
||||
}
|
||||
|
||||
|
||||
// MARK: - Private Methods
|
||||
|
||||
|
||||
private func getMentionSuggestions(_ text: String, peers: [String]) -> ([String], NSRange)? {
|
||||
guard let regex = mentionRegex else { return nil }
|
||||
|
||||
let nsText = text as NSString
|
||||
let matches = regex.matches(in: text, options: [], range: NSRange(location: 0, length: nsText.length))
|
||||
|
||||
let matches = Patterns.mentionAutocomplete.matches(
|
||||
in: text,
|
||||
options: [],
|
||||
range: NSRange(location: 0, length: nsText.length)
|
||||
)
|
||||
|
||||
guard let match = matches.last else { return nil }
|
||||
|
||||
|
||||
let fullRange = match.range(at: 0)
|
||||
let captureRange = match.range(at: 1)
|
||||
let prefix = nsText.substring(with: captureRange).normalizedNickname.lowercased()
|
||||
@ -62,10 +60,10 @@ final class AutocompleteService {
|
||||
.sorted()
|
||||
.prefix(5)
|
||||
.map { "@\($0)" }
|
||||
|
||||
|
||||
return suggestions.isEmpty ? nil : (Array(suggestions), fullRange)
|
||||
}
|
||||
|
||||
|
||||
private func needsArgument(command: String) -> Bool {
|
||||
switch command {
|
||||
case "/who", "/clear":
|
||||
|
||||
@ -43,6 +43,9 @@ final class MessageFormattingEngine {
|
||||
|
||||
static let mention = SafeRegex.compile("@([\\p{L}0-9_]+(?:#[a-fA-F0-9]{4})?)")
|
||||
|
||||
/// Trailing partial `@nickname` at the composer cursor — autocomplete only.
|
||||
static let mentionAutocomplete = SafeRegex.compile("@([\\p{L}0-9_]*)$")
|
||||
|
||||
static let cashu = SafeRegex.compile("\\bcashu[AB][A-Za-z0-9._-]{40,}\\b")
|
||||
|
||||
static let bolt11 = SafeRegex.compile("(?i)\\bln(bc|tb|bcrt)[0-9][a-z0-9]{50,}\\b")
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user