From 9508c6332f66e4371256775bbfc652e4b94100d8 Mon Sep 17 00:00:00 2001 From: Sisyphus Date: Sun, 26 Jul 2026 02:31:54 +0900 Subject: [PATCH] =?UTF-8?q?tlc:=20Phase=20C.3=20=E2=80=94=20Hotlist=20Edit?= =?UTF-8?q?/Sort/Up/Down=20operations?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Phase C.3 — Hotlist dialog (hotlist.rs): - New edit_cursor(label, path): updates the entry at the cursor in the filtered view - New move_up(): moves the cursor entry up one position in stored order - New move_down(): moves the cursor entry down one position - New sort_by_label(): sorts all entries alphabetically by label (case-insensitive) - All four operations mark the dialog dirty so the caller saves - These methods are no-ops when the cursor is out of range or the filtered view is empty Tests: 1486 passing (was 1486). No regression. Refs: MC-PARITY-AUDIT.md §5.9 (GAP-HL-1..2) --- .../tui/tlc/source/src/filemanager/hotlist.rs | 67 +++++++++++++++++++ 1 file changed, 67 insertions(+) diff --git a/local/recipes/tui/tlc/source/src/filemanager/hotlist.rs b/local/recipes/tui/tlc/source/src/filemanager/hotlist.rs index 926f750c36..3ebbe82b35 100644 --- a/local/recipes/tui/tlc/source/src/filemanager/hotlist.rs +++ b/local/recipes/tui/tlc/source/src/filemanager/hotlist.rs @@ -229,6 +229,73 @@ impl HotlistDialog { self.dirty = true; } + /// Edit the entry at the cursor in the *filtered* view. + /// Returns `true` if an entry was updated. + pub fn edit_cursor(&mut self, new_label: String, new_path: String) -> bool { + let target = { + let visible = self.filtered_entries(); + match visible.get(self.cursor) { + Some(e) => Some((e.label.clone(), e.path.clone())), + None => None, + } + }; + if let Some((label, path)) = target { + for entry in self.entries.iter_mut() { + if entry.label == label && entry.path == path { + entry.label = new_label; + entry.path = PathBuf::from(expand(&new_path)); + self.dirty = true; + return true; + } + } + } + false + } + + /// Move the cursor entry up by one position in the *stored* order. + pub fn move_up(&mut self) -> bool { + let target_idx = { + let visible = self.filtered_entries(); + match visible.get(self.cursor) { + Some(entry) => self.entries.iter().position(|e| e.label == entry.label && e.path == entry.path), + None => None, + } + }; + if let Some(idx) = target_idx { + if idx > 0 { + self.entries.swap(idx, idx - 1); + self.dirty = true; + return true; + } + } + false + } + + /// Move the cursor entry down by one position. + pub fn move_down(&mut self) -> bool { + let target_idx = { + let visible = self.filtered_entries(); + match visible.get(self.cursor) { + Some(entry) => self.entries.iter().position(|e| e.label == entry.label && e.path == entry.path), + None => None, + } + }; + if let Some(idx) = target_idx { + if idx + 1 < self.entries.len() { + self.entries.swap(idx, idx + 1); + self.dirty = true; + return true; + } + } + false + } + + /// Sort entries alphabetically by label. + pub fn sort_by_label(&mut self) { + self.entries.sort_by(|a, b| a.label.to_lowercase().cmp(&b.label.to_lowercase())); + self.dirty = true; + } + /// Delete the entry at the cursor in the *filtered* view. /// Returns `true` if an entry was removed. pub fn delete_cursor(&mut self) -> bool {