From 1ec01bb4e3e5f3c66361b7f91bcd3a22a4f86ad7 Mon Sep 17 00:00:00 2001 From: "Dhanji R. Prasanna" Date: Tue, 20 Jan 2026 13:22:06 +0530 Subject: [PATCH] Limit /resume completion to 8 most recent sessions Always shows at most 8 sessions in tab completion, sorted by newest first. This applies whether the user types /resume or /resume abc. Implementation: - list_sessions() returns all sessions sorted by mtime (newest first) - Completion filters by prefix, then takes first 8 matches --- crates/g3-cli/src/completion.rs | 32 +++++++++++++++++++++++++------- 1 file changed, 25 insertions(+), 7 deletions(-) diff --git a/crates/g3-cli/src/completion.rs b/crates/g3-cli/src/completion.rs index 0197a73..a84e336 100644 --- a/crates/g3-cli/src/completion.rs +++ b/crates/g3-cli/src/completion.rs @@ -129,23 +129,39 @@ impl G3Helper { result } - /// List available session IDs from .g3/sessions/ - fn list_sessions(&self) -> Vec { + /// List available session IDs from .g3/sessions/, sorted by newest first. + /// If `limit` is Some(n), returns at most n sessions. + fn list_sessions(&self, limit: Option) -> Vec { let sessions_dir = PathBuf::from(".g3/sessions"); if !sessions_dir.is_dir() { return Vec::new(); } - std::fs::read_dir(&sessions_dir) + let mut sessions: Vec<_> = std::fs::read_dir(&sessions_dir) .ok() .map(|entries| { entries .filter_map(|entry| entry.ok()) .filter(|entry| entry.path().is_dir()) - .map(|entry| entry.file_name().to_string_lossy().to_string()) + .filter_map(|entry| { + let modified = entry.metadata().ok()?.modified().ok()?; + Some((entry.file_name().to_string_lossy().to_string(), modified)) + }) .collect() }) - .unwrap_or_default() + .unwrap_or_default(); + + // Sort by modification time, newest first + sessions.sort_by(|a, b| b.1.cmp(&a.1)); + + // Apply limit if specified + let sessions: Vec = sessions + .into_iter() + .map(|(name, _)| name) + .take(limit.unwrap_or(usize::MAX)) + .collect(); + + sessions } } @@ -261,7 +277,8 @@ impl Completer for G3Helper { // Case 4: Session ID completion for /resume command if line_to_cursor.starts_with("/resume ") { let partial = word; - let sessions = self.list_sessions(); + // Get all sessions sorted by newest first, then filter and limit + let sessions = self.list_sessions(None); let matches: Vec = sessions .into_iter() .filter(|s| s.starts_with(partial)) @@ -269,6 +286,7 @@ impl Completer for G3Helper { display: s.clone(), replacement: s, }) + .take(8) // Show at most 8 most recent matches .collect(); return Ok((word_start, matches)); } @@ -537,7 +555,7 @@ mod tests { // Test list_sessions directly - should not panic regardless of whether // .g3/sessions exists or not - let sessions = helper.list_sessions(); + let sessions = helper.list_sessions(None); // This will either return sessions (if .g3/sessions exists) or empty // The important thing is it doesn't panic