1- use std:: { sync:: Arc , time:: Duration } ;
1+ use std:: { cmp :: Reverse , sync:: Arc , time:: Duration } ;
22
3+ use fuzzy_matcher:: { FuzzyMatcher , skim:: SkimMatcherV2 } ;
4+ use itertools:: Itertools ;
35use poise:: {
46 CreateReply , ReplyHandle ,
57 serenity_prelude:: { self as serenity, AutocompleteChoice } ,
@@ -8,7 +10,7 @@ use server_shared::qunet::server::Server;
810use thiserror:: Error ;
911
1012use crate :: {
11- core:: handler:: ConnectionHandler ,
13+ core:: handler:: { ClientStateHandle , ConnectionHandler } ,
1214 discord:: { BotError , state:: BotState } ,
1315 users:: { ComputedRole , DbUser , UserPunishmentType , UsersModule } ,
1416} ;
@@ -131,24 +133,75 @@ pub fn parse_duration_str(s: &str) -> Result<Duration, ParseDurationError> {
131133 Ok ( Duration :: from_secs ( number * modifier) )
132134}
133135
134- pub async fn online_user_autocomplete ( ctx : Context < ' _ > , partial : & str ) -> Vec < AutocompleteChoice > {
136+ fn fuzzy_match ( target : & str , candidate : & str ) -> i64 {
137+ let matcher = SkimMatcherV2 :: default ( ) ;
138+ matcher. fuzzy_match ( target, candidate) . unwrap_or ( -1 )
139+ }
140+
141+ fn wrap_user_autocomplete < ' a > (
142+ query : & str ,
143+ iter : impl Iterator < Item = ( & ' a str , i32 ) > ,
144+ ) -> Vec < AutocompleteChoice > {
145+ iter. sorted_by_key ( |( username, id) | {
146+ if let Ok ( query_id) = query. parse :: < i32 > ( ) {
147+ if * id == query_id {
148+ return Reverse ( i64:: MAX ) ; // highest priority if ID matches
149+ }
150+ }
151+
152+ if username. eq_ignore_ascii_case ( query) {
153+ return Reverse ( i64:: MAX - 1 ) ; // second highest priority if username matches
154+ }
155+
156+ // fuzzy match on username
157+ Reverse ( fuzzy_match ( username, query) )
158+ } )
159+ . map ( |( username, id) | AutocompleteChoice :: new ( username. to_owned ( ) , id. to_string ( ) ) )
160+ . take ( 10 )
161+ . collect ( )
162+ }
163+
164+ fn get_online_users_matching ( ctx : Context < ' _ > , partial : & str ) -> Vec < ClientStateHandle > {
135165 let server = ctx. data ( ) . server ( ) . unwrap ( ) ;
136- let clients = server. handler ( ) . get_n_clients_matching ( partial, 5 ) ;
166+ let mut clients = server. handler ( ) . get_n_clients_matching ( partial, 10 ) ;
167+
168+ if let Ok ( query_id) = partial. parse :: < i32 > ( ) {
169+ if let Some ( client) = server. handler ( ) . find_client ( query_id) {
170+ clients. push ( client) ;
171+ }
172+ }
137173
138174 clients
139- . into_iter ( )
140- . map ( |c| AutocompleteChoice :: new ( c. username ( ) . to_string ( ) , c. account_id ( ) . to_string ( ) ) )
141- . collect ( )
142175}
143176
144- // async fn db_user_autocomplete (ctx: Context<'_>, partial: &str) -> Vec<AutocompleteChoice > {
145- // let server = ctx.data().server().unwrap();
146- // let users = server.handler().module::<UsersModule>();
177+ async fn get_db_users_matching ( ctx : Context < ' _ > , partial : & str ) -> Vec < DbUser > {
178+ let server = ctx. data ( ) . server ( ) . unwrap ( ) ;
179+ let users = server. handler ( ) . module :: < UsersModule > ( ) ;
147180
148- // users.query_user();
181+ users. query_matching_users ( partial, 50 ) . await . unwrap_or_default ( )
182+ }
149183
150- // clients
151- // .into_iter()
152- // .map(|c| AutocompleteChoice::new(c.username().to_string(), c.account_id().to_string()))
153- // .collect()
154- // }
184+ pub async fn online_user_autocomplete ( ctx : Context < ' _ > , partial : & str ) -> Vec < AutocompleteChoice > {
185+ let clients = get_online_users_matching ( ctx, partial) ;
186+ wrap_user_autocomplete ( partial, clients. iter ( ) . map ( |c| ( c. username ( ) , c. account_id ( ) ) ) )
187+ }
188+
189+ pub async fn db_user_autocomplete ( ctx : Context < ' _ > , partial : & str ) -> Vec < AutocompleteChoice > {
190+ let users = get_db_users_matching ( ctx, partial) . await ;
191+ wrap_user_autocomplete ( partial, users. iter ( ) . map ( |u| ( u. username ( ) , u. account_id ) ) )
192+ }
193+
194+ pub async fn online_and_db_user_autocomplete (
195+ ctx : Context < ' _ > ,
196+ partial : & str ,
197+ ) -> Vec < AutocompleteChoice > {
198+ let mut vec = Vec :: new ( ) ;
199+
200+ let first = get_online_users_matching ( ctx, partial) ;
201+ vec. extend ( first. iter ( ) . map ( |c| ( c. username ( ) , c. account_id ( ) ) ) ) ;
202+
203+ let second = get_db_users_matching ( ctx, partial) . await ;
204+ vec. extend ( second. iter ( ) . map ( |u| ( u. username ( ) , u. account_id ) ) ) ;
205+
206+ wrap_user_autocomplete ( partial, vec. into_iter ( ) )
207+ }
0 commit comments