Skip to content

Commit

Permalink
feat(channels): add support for multi selection (#234)
Browse files Browse the repository at this point in the history
Fixes #229 

<img width="1793" alt="Screenshot 2025-01-07 at 00 12 18"
src="https://github.com/user-attachments/assets/f2158c70-b3ab-4c14-8856-eb8463efef8a"
/>
  • Loading branch information
alexpasmantier authored Jan 6, 2025
1 parent d207848 commit 2e5f65b
Show file tree
Hide file tree
Showing 34 changed files with 471 additions and 73 deletions.
8 changes: 6 additions & 2 deletions .config/config.toml
Original file line number Diff line number Diff line change
Expand Up @@ -83,8 +83,12 @@ select_prev_page = "pageup"
# Scrolling the preview pane
scroll_preview_half_page_down = "ctrl-d"
scroll_preview_half_page_up = "ctrl-u"
# Select an entry
select_entry = "enter"
# Add entry to selection and move to the next entry
toggle_selection_down = "tab"
# Add entry to selection and move to the previous entry
toggle_selection_up = "backtab"
# Confirm selection
confirm_selection = "enter"
# Copy the selected entry to the clipboard
copy_entry_to_clipboard = "ctrl-y"
# Toggle the remote control mode
Expand Down
8 changes: 8 additions & 0 deletions crates/television-channels/src/channels.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
use std::collections::HashSet;

use crate::entry::Entry;
use color_eyre::Result;
use television_derive::{Broadcast, ToCliChannel, ToUnitChannel};
Expand Down Expand Up @@ -65,6 +67,12 @@ pub trait OnAir: Send {
/// Get a specific result by its index.
fn get_result(&self, index: u32) -> Option<Entry>;

/// Get the currently selected entries.
fn selected_entries(&self) -> &HashSet<Entry>;

/// Toggles selection for the entry under the cursor.
fn toggle_selection(&mut self, entry: &Entry);

/// Get the number of results currently available.
fn result_count(&self) -> u32;

Expand Down
16 changes: 16 additions & 0 deletions crates/television-channels/src/channels/alias.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
use std::collections::HashSet;

use crate::channels::OnAir;
use crate::entry::Entry;
use crate::entry::PreviewType;
Expand All @@ -21,6 +23,7 @@ impl Alias {
pub struct Channel {
matcher: Matcher<Alias>,
file_icon: FileIcon,
selected_entries: HashSet<Entry>,
}

const NUM_THREADS: usize = 1;
Expand Down Expand Up @@ -52,6 +55,7 @@ impl Channel {
Self {
matcher,
file_icon: FileIcon::from(FILE_ICON_STR),
selected_entries: HashSet::new(),
}
}
}
Expand Down Expand Up @@ -115,6 +119,18 @@ impl OnAir for Channel {
})
}

fn selected_entries(&self) -> &HashSet<Entry> {
&self.selected_entries
}

fn toggle_selection(&mut self, entry: &Entry) {
if self.selected_entries.contains(entry) {
self.selected_entries.remove(entry);
} else {
self.selected_entries.insert(entry.clone());
}
}

fn result_count(&self) -> u32 {
self.matcher.matched_item_count
}
Expand Down
14 changes: 14 additions & 0 deletions crates/television-channels/src/channels/cable.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ pub struct Channel {
matcher: Matcher<String>,
entries_command: String,
preview_kind: PreviewKind,
selected_entries: HashSet<Entry>,
}

impl Default for Channel {
Expand Down Expand Up @@ -93,6 +94,7 @@ impl Channel {
entries_command: entries_command.to_string(),
preview_kind,
name: name.to_string(),
selected_entries: HashSet::new(),
}
}
}
Expand Down Expand Up @@ -162,6 +164,18 @@ impl OnAir for Channel {
})
}

fn selected_entries(&self) -> &HashSet<Entry> {
&self.selected_entries
}

fn toggle_selection(&mut self, entry: &Entry) {
if self.selected_entries.contains(entry) {
self.selected_entries.remove(entry);
} else {
self.selected_entries.insert(entry.clone());
}
}

fn result_count(&self) -> u32 {
self.matcher.matched_item_count
}
Expand Down
14 changes: 14 additions & 0 deletions crates/television-channels/src/channels/dirs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ pub struct Channel {
crawl_handle: tokio::task::JoinHandle<()>,
// PERF: cache results (to make deleting characters smoother) with
// a shallow stack of sub-patterns as keys (e.g. "a", "ab", "abc")
selected_entries: HashSet<Entry>,
}

impl Channel {
Expand All @@ -21,6 +22,7 @@ impl Channel {
Channel {
matcher,
crawl_handle,
selected_entries: HashSet::new(),
}
}
}
Expand Down Expand Up @@ -104,6 +106,18 @@ impl OnAir for Channel {
})
}

fn selected_entries(&self) -> &HashSet<Entry> {
&self.selected_entries
}

fn toggle_selection(&mut self, entry: &Entry) {
if self.selected_entries.contains(entry) {
self.selected_entries.remove(entry);
} else {
self.selected_entries.insert(entry.clone());
}
}

fn result_count(&self) -> u32 {
self.matcher.matched_item_count
}
Expand Down
16 changes: 16 additions & 0 deletions crates/television-channels/src/channels/env.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
use std::collections::HashSet;

use devicons::FileIcon;

use super::OnAir;
Expand All @@ -15,6 +17,7 @@ struct EnvVar {
pub struct Channel {
matcher: Matcher<EnvVar>,
file_icon: FileIcon,
selected_entries: HashSet<Entry>,
}

const NUM_THREADS: usize = 1;
Expand All @@ -32,6 +35,7 @@ impl Channel {
Channel {
matcher,
file_icon: FileIcon::from(FILE_ICON_STR),
selected_entries: HashSet::new(),
}
}
}
Expand Down Expand Up @@ -95,6 +99,18 @@ impl OnAir for Channel {
})
}

fn selected_entries(&self) -> &HashSet<Entry> {
&self.selected_entries
}

fn toggle_selection(&mut self, entry: &Entry) {
if self.selected_entries.contains(entry) {
self.selected_entries.remove(entry);
} else {
self.selected_entries.insert(entry.clone());
}
}

fn result_count(&self) -> u32 {
self.matcher.matched_item_count
}
Expand Down
14 changes: 14 additions & 0 deletions crates/television-channels/src/channels/files.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ pub struct Channel {
crawl_handle: tokio::task::JoinHandle<()>,
// PERF: cache results (to make deleting characters smoother) with
// a shallow stack of sub-patterns as keys (e.g. "a", "ab", "abc")
selected_entries: HashSet<Entry>,
}

impl Channel {
Expand All @@ -21,6 +22,7 @@ impl Channel {
Channel {
matcher,
crawl_handle,
selected_entries: HashSet::new(),
}
}
}
Expand Down Expand Up @@ -106,6 +108,18 @@ impl OnAir for Channel {
})
}

fn selected_entries(&self) -> &HashSet<Entry> {
&self.selected_entries
}

fn toggle_selection(&mut self, entry: &Entry) {
if self.selected_entries.contains(entry) {
self.selected_entries.remove(entry);
} else {
self.selected_entries.insert(entry.clone());
}
}

fn result_count(&self) -> u32 {
self.matcher.matched_item_count
}
Expand Down
15 changes: 15 additions & 0 deletions crates/television-channels/src/channels/git_repos.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ use devicons::FileIcon;
use directories::BaseDirs;
use ignore::overrides::OverrideBuilder;
use lazy_static::lazy_static;
use std::collections::HashSet;
use std::path::PathBuf;
use tokio::task::JoinHandle;
use tracing::debug;
Expand All @@ -15,6 +16,7 @@ pub struct Channel {
matcher: Matcher<String>,
icon: FileIcon,
crawl_handle: JoinHandle<()>,
selected_entries: HashSet<Entry>,
}

impl Channel {
Expand All @@ -29,6 +31,7 @@ impl Channel {
matcher,
icon: FileIcon::from("git"),
crawl_handle,
selected_entries: HashSet::new(),
}
}
}
Expand Down Expand Up @@ -81,6 +84,18 @@ impl OnAir for Channel {
})
}

fn selected_entries(&self) -> &HashSet<Entry> {
&self.selected_entries
}

fn toggle_selection(&mut self, entry: &Entry) {
if self.selected_entries.contains(entry) {
self.selected_entries.remove(entry);
} else {
self.selected_entries.insert(entry.clone());
}
}

fn result_count(&self) -> u32 {
self.matcher.matched_item_count
}
Expand Down
10 changes: 10 additions & 0 deletions crates/television-channels/src/channels/remote_control.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
use std::collections::HashSet;
use std::fmt::Display;

use crate::cable::{CableChannelPrototype, CableChannels};
Expand All @@ -13,6 +14,7 @@ use super::cable;
pub struct RemoteControl {
matcher: Matcher<RCButton>,
cable_channels: Option<CableChannels>,
selected_entries: HashSet<Entry>,
}

#[derive(Clone)]
Expand Down Expand Up @@ -59,6 +61,7 @@ impl RemoteControl {
RemoteControl {
matcher,
cable_channels,
selected_entries: HashSet::new(),
}
}

Expand Down Expand Up @@ -140,6 +143,13 @@ impl OnAir for RemoteControl {
.collect()
}

fn selected_entries(&self) -> &HashSet<Entry> {
&self.selected_entries
}

#[allow(unused_variables)]
fn toggle_selection(&mut self, entry: &Entry) {}

fn get_result(&self, index: u32) -> Option<Entry> {
self.matcher.get_result(index).map(|item| {
let path = item.matched_string;
Expand Down
15 changes: 15 additions & 0 deletions crates/television-channels/src/channels/stdin.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
use std::{
collections::HashSet,
io::{stdin, BufRead},
thread::spawn,
};
Expand All @@ -12,6 +13,7 @@ use television_fuzzy::matcher::{config::Config, injector::Injector, Matcher};
pub struct Channel {
matcher: Matcher<String>,
preview_type: PreviewType,
selected_entries: HashSet<Entry>,
}

impl Channel {
Expand All @@ -24,6 +26,7 @@ impl Channel {
Self {
matcher,
preview_type: preview_type.unwrap_or_default(),
selected_entries: HashSet::new(),
}
}
}
Expand Down Expand Up @@ -90,6 +93,18 @@ impl OnAir for Channel {
})
}

fn selected_entries(&self) -> &HashSet<Entry> {
&self.selected_entries
}

fn toggle_selection(&mut self, entry: &Entry) {
if self.selected_entries.contains(entry) {
self.selected_entries.remove(entry);
} else {
self.selected_entries.insert(entry.clone());
}
}

fn result_count(&self) -> u32 {
self.matcher.matched_item_count
}
Expand Down
17 changes: 17 additions & 0 deletions crates/television-channels/src/channels/text.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ use crate::entry::{Entry, PreviewType};
use devicons::FileIcon;
use ignore::WalkState;
use std::{
collections::HashSet,
fs::File,
io::{BufRead, Read, Seek},
path::{Path, PathBuf},
Expand Down Expand Up @@ -36,6 +37,7 @@ impl CandidateLine {
pub struct Channel {
matcher: Matcher<CandidateLine>,
crawl_handle: tokio::task::JoinHandle<()>,
selected_entries: HashSet<Entry>,
}

impl Channel {
Expand All @@ -49,6 +51,7 @@ impl Channel {
Channel {
matcher,
crawl_handle,
selected_entries: HashSet::new(),
}
}

Expand All @@ -73,6 +76,7 @@ impl Channel {
Channel {
matcher,
crawl_handle,
selected_entries: HashSet::new(),
}
}

Expand All @@ -97,6 +101,7 @@ impl Channel {
Channel {
matcher,
crawl_handle: load_handle,
selected_entries: HashSet::new(),
}
}
}
Expand Down Expand Up @@ -195,6 +200,18 @@ impl OnAir for Channel {
})
}

fn selected_entries(&self) -> &HashSet<Entry> {
&self.selected_entries
}

fn toggle_selection(&mut self, entry: &Entry) {
if self.selected_entries.contains(entry) {
self.selected_entries.remove(entry);
} else {
self.selected_entries.insert(entry.clone());
}
}

fn result_count(&self) -> u32 {
self.matcher.matched_item_count
}
Expand Down
Loading

0 comments on commit 2e5f65b

Please sign in to comment.