From e0bd311e849333968f110898c236a6b6a3a03e20 Mon Sep 17 00:00:00 2001 From: Kyle Sutherland-Cash Date: Tue, 18 Jul 2023 18:12:51 +0100 Subject: [PATCH] fix(sessions): use custom lists of adjectives and nouns for generating session names (#2122) * Create custom lists of adjectives and nouns for generating session names * move word lists to const slices * add logic to retry name generation * refactor - reuse the name generator - iterator instead of for loop --------- Co-authored-by: Thomas Linford --- src/commands.rs | 25 +++++++- src/sessions.rs | 148 ++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 170 insertions(+), 3 deletions(-) diff --git a/src/commands.rs b/src/commands.rs index 697f7057f7..6e5608e10e 100644 --- a/src/commands.rs +++ b/src/commands.rs @@ -2,7 +2,7 @@ use dialoguer::Confirm; use std::{fs::File, io::prelude::*, path::PathBuf, process}; use crate::sessions::{ - assert_session, assert_session_ne, get_active_session, get_sessions, + assert_session, assert_session_ne, get_active_session, get_name_generator, get_sessions, get_sessions_sorted_by_mtime, kill_session as kill_session_impl, match_session_name, print_sessions, print_sessions_with_index, session_exists, ActiveSession, SessionNameMatch, }; @@ -93,7 +93,7 @@ pub(crate) fn start_server(path: PathBuf, debug: bool) { } fn create_new_client() -> ClientInfo { - ClientInfo::New(names::Generator::default().next().unwrap()) + ClientInfo::New(generate_unique_session_name()) } fn find_indexed_session( @@ -446,7 +446,7 @@ pub(crate) fn start_client(opts: CliArgs) { process::exit(0); } - let session_name = names::Generator::default().next().unwrap(); + let session_name = generate_unique_session_name(); start_client_plan(session_name.clone()); start_client_impl( Box::new(os_input), @@ -459,3 +459,22 @@ pub(crate) fn start_client(opts: CliArgs) { } } } + +fn generate_unique_session_name() -> String { + let sessions = get_sessions(); + let Ok(sessions) = sessions else { + eprintln!("Failed to list existing sessions: {:?}", sessions); + process::exit(1); + }; + + let name = get_name_generator() + .take(1000) + .find(|name| !sessions.contains(name)); + + if let Some(name) = name { + return name; + } else { + eprintln!("Failed to generate a unique session name, giving up"); + process::exit(1); + } +} diff --git a/src/sessions.rs b/src/sessions.rs index 9c7de37e9f..910bd333b4 100644 --- a/src/sessions.rs +++ b/src/sessions.rs @@ -219,3 +219,151 @@ pub(crate) fn assert_session_ne(name: &str) { }; process::exit(1); } + +/// Create a new random name generator +/// +/// Used to provide a memorable handle for a session when users don't specify a session name when the session is +/// created. +/// +/// Uses the list of adjectives and nouns defined below, with the intention of avoiding unfortunate +/// and offensive combinations. Care should be taken when adding or removing to either list due to the birthday paradox/ +/// hash collisions, e.g. with 4096 unique names, the likelihood of a collision in 10 session names is 1%. +pub(crate) fn get_name_generator() -> impl Iterator { + names::Generator::new(&ADJECTIVES, &NOUNS, names::Name::Plain) +} + +const ADJECTIVES: &[&'static str] = &[ + "adamant", + "adept", + "adventurous", + "arcadian", + "auspicious", + "awesome", + "blossoming", + "brave", + "charming", + "chatty", + "circular", + "considerate", + "cubic", + "curious", + "delighted", + "didactic", + "diligent", + "effulgent", + "erudite", + "excellent", + "exquisite", + "fabulous", + "fascinating", + "friendly", + "glowing", + "gracious", + "gregarious", + "hopeful", + "implacable", + "inventive", + "joyous", + "judicious", + "jumping", + "kind", + "likable", + "loyal", + "lucky", + "marvellous", + "mellifluous", + "nautical", + "oblong", + "outstanding", + "polished", + "polite", + "profound", + "quadratic", + "quiet", + "rectangular", + "remarkable", + "rusty", + "sensible", + "sincere", + "sparkling", + "splendid", + "stellar", + "tenacious", + "tremendous", + "triangular", + "undulating", + "unflappable", + "unique", + "verdant", + "vitreous", + "wise", + "zippy", +]; + +const NOUNS: &[&'static str] = &[ + "aardvark", + "accordion", + "apple", + "apricot", + "bee", + "brachiosaur", + "cactus", + "capsicum", + "clarinet", + "cowbell", + "crab", + "cuckoo", + "cymbal", + "diplodocus", + "donkey", + "drum", + "duck", + "echidna", + "elephant", + "foxglove", + "galaxy", + "glockenspiel", + "goose", + "hill", + "horse", + "iguanadon", + "jellyfish", + "kangaroo", + "lake", + "lemon", + "lemur", + "magpie", + "megalodon", + "mountain", + "mouse", + "muskrat", + "newt", + "oboe", + "ocelot", + "orange", + "panda", + "peach", + "pepper", + "petunia", + "pheasant", + "piano", + "pigeon", + "platypus", + "quasar", + "rhinoceros", + "river", + "rustacean", + "salamander", + "sitar", + "stegosaurus", + "tambourine", + "tiger", + "tomato", + "triceratops", + "ukulele", + "viola", + "weasel", + "xylophone", + "yak", + "zebra", +];