mirror of
https://github.com/alexpasmantier/television.git
synced 2025-06-06 19:45:23 +00:00
feat(cli): add a --no-remote
flag to lock the application on the cli-invoked channel (#455)
This will disable the remote control panel and associated actions entirely. This is useful when the remote control is not needed or when the user wants `tv` to run in single-channel mode (e.g. when using it as a file picker for a script or embedding it in a larger application).
This commit is contained in:
parent
4a584b437c
commit
b81873738a
@ -100,6 +100,7 @@ impl App {
|
||||
config: Config,
|
||||
input: Option<String>,
|
||||
select_1: bool,
|
||||
no_remote: bool,
|
||||
) -> Self {
|
||||
let (action_tx, action_rx) = mpsc::unbounded_channel();
|
||||
let (render_tx, render_rx) = mpsc::unbounded_channel();
|
||||
@ -110,8 +111,13 @@ impl App {
|
||||
|
||||
debug!("{:?}", keymap);
|
||||
let (ui_state_tx, ui_state_rx) = mpsc::unbounded_channel();
|
||||
let television =
|
||||
Television::new(action_tx.clone(), channel, config, input);
|
||||
let television = Television::new(
|
||||
action_tx.clone(),
|
||||
channel,
|
||||
config,
|
||||
input,
|
||||
no_remote,
|
||||
);
|
||||
|
||||
Self {
|
||||
keymap,
|
||||
@ -401,6 +407,7 @@ mod test {
|
||||
Config::default(),
|
||||
None,
|
||||
true,
|
||||
false,
|
||||
);
|
||||
app.television
|
||||
.results_picker
|
||||
|
@ -102,6 +102,16 @@ pub struct Cli {
|
||||
#[arg(long, default_value = "false", verbatim_doc_comment)]
|
||||
pub select_1: bool,
|
||||
|
||||
/// Disable the remote control.
|
||||
///
|
||||
/// This will disable the remote control panel and associated actions
|
||||
/// entirely. This is useful when the remote control is not needed or
|
||||
/// when the user wants `tv` to run in single-channel mode (e.g. when
|
||||
/// using it as a file picker for a script or embedding it in a larger
|
||||
/// application).
|
||||
#[arg(long, default_value = "false", verbatim_doc_comment)]
|
||||
pub no_remote: bool,
|
||||
|
||||
#[command(subcommand)]
|
||||
pub command: Option<Command>,
|
||||
}
|
||||
|
@ -30,6 +30,7 @@ pub struct PostProcessedCli {
|
||||
pub autocomplete_prompt: Option<String>,
|
||||
pub keybindings: Option<KeyBindings>,
|
||||
pub select_1: bool,
|
||||
pub no_remote: bool,
|
||||
}
|
||||
|
||||
impl Default for PostProcessedCli {
|
||||
@ -46,6 +47,7 @@ impl Default for PostProcessedCli {
|
||||
autocomplete_prompt: None,
|
||||
keybindings: None,
|
||||
select_1: false,
|
||||
no_remote: false,
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -111,6 +113,7 @@ impl From<Cli> for PostProcessedCli {
|
||||
autocomplete_prompt: cli.autocomplete_prompt,
|
||||
keybindings,
|
||||
select_1: cli.select_1,
|
||||
no_remote: cli.no_remote,
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -326,6 +329,7 @@ mod tests {
|
||||
working_directory: Some("/home/user".to_string()),
|
||||
autocomplete_prompt: None,
|
||||
select_1: false,
|
||||
no_remote: false,
|
||||
};
|
||||
|
||||
let post_processed_cli: PostProcessedCli = cli.into();
|
||||
@ -365,6 +369,7 @@ mod tests {
|
||||
working_directory: None,
|
||||
autocomplete_prompt: None,
|
||||
select_1: false,
|
||||
no_remote: false,
|
||||
};
|
||||
|
||||
let post_processed_cli: PostProcessedCli = cli.into();
|
||||
@ -395,6 +400,7 @@ mod tests {
|
||||
working_directory: None,
|
||||
autocomplete_prompt: None,
|
||||
select_1: false,
|
||||
no_remote: false,
|
||||
};
|
||||
|
||||
let post_processed_cli: PostProcessedCli = cli.into();
|
||||
@ -420,6 +426,7 @@ mod tests {
|
||||
working_directory: None,
|
||||
autocomplete_prompt: None,
|
||||
select_1: false,
|
||||
no_remote: false,
|
||||
};
|
||||
|
||||
let post_processed_cli: PostProcessedCli = cli.into();
|
||||
@ -448,6 +455,7 @@ mod tests {
|
||||
working_directory: None,
|
||||
autocomplete_prompt: None,
|
||||
select_1: false,
|
||||
no_remote: false,
|
||||
};
|
||||
|
||||
let post_processed_cli: PostProcessedCli = cli.into();
|
||||
|
@ -65,7 +65,8 @@ async fn main() -> Result<()> {
|
||||
CLIPBOARD.with(<_>::default);
|
||||
|
||||
debug!("Creating application...");
|
||||
let mut app = App::new(channel, config, args.input, args.select_1);
|
||||
let mut app =
|
||||
App::new(channel, config, args.input, args.select_1, args.no_remote);
|
||||
stdout().flush()?;
|
||||
debug!("Running application...");
|
||||
let output = app.run(stdout().is_terminal(), false).await?;
|
||||
|
@ -35,7 +35,7 @@ pub struct Television {
|
||||
action_tx: UnboundedSender<Action>,
|
||||
pub config: Config,
|
||||
pub channel: TelevisionChannel,
|
||||
pub remote_control: TelevisionChannel,
|
||||
pub remote_control: Option<TelevisionChannel>,
|
||||
pub mode: Mode,
|
||||
pub current_pattern: String,
|
||||
pub results_picker: Picker,
|
||||
@ -57,6 +57,7 @@ impl Television {
|
||||
mut channel: TelevisionChannel,
|
||||
config: Config,
|
||||
input: Option<String>,
|
||||
no_remote: bool,
|
||||
) -> Self {
|
||||
let mut results_picker = Picker::new(input.clone());
|
||||
if config.ui.input_bar_position == InputPosition::Bottom {
|
||||
@ -87,13 +88,20 @@ impl Television {
|
||||
None,
|
||||
);
|
||||
|
||||
let remote_control = if no_remote {
|
||||
None
|
||||
} else {
|
||||
Some(TelevisionChannel::RemoteControl(RemoteControl::new(
|
||||
builtin_channels,
|
||||
Some(cable_channels),
|
||||
)))
|
||||
};
|
||||
|
||||
Self {
|
||||
action_tx,
|
||||
config,
|
||||
channel,
|
||||
remote_control: TelevisionChannel::RemoteControl(
|
||||
RemoteControl::new(builtin_channels, Some(cable_channels)),
|
||||
),
|
||||
remote_control,
|
||||
mode: Mode::Channel,
|
||||
current_pattern: EMPTY_STRING.to_string(),
|
||||
results_picker,
|
||||
@ -118,9 +126,9 @@ impl Television {
|
||||
let builtin_channels = load_builtin_channels(Some(
|
||||
&cable_channels.keys().collect::<Vec<_>>(),
|
||||
));
|
||||
self.remote_control = TelevisionChannel::RemoteControl(
|
||||
self.remote_control = Some(TelevisionChannel::RemoteControl(
|
||||
RemoteControl::new(builtin_channels, Some(cable_channels)),
|
||||
);
|
||||
));
|
||||
}
|
||||
|
||||
pub fn dump_context(&self) -> Ctx {
|
||||
@ -170,7 +178,7 @@ impl Television {
|
||||
self.channel.find(pattern);
|
||||
}
|
||||
Mode::RemoteControl | Mode::SendToChannel => {
|
||||
self.remote_control.find(pattern);
|
||||
self.remote_control.as_mut().unwrap().find(pattern);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -188,6 +196,8 @@ impl Television {
|
||||
if let Some(i) = self.rc_picker.selected() {
|
||||
return self
|
||||
.remote_control
|
||||
.as_ref()
|
||||
.unwrap()
|
||||
.get_result(i.try_into().unwrap());
|
||||
}
|
||||
None
|
||||
@ -217,9 +227,10 @@ impl Television {
|
||||
Mode::Channel => {
|
||||
(self.channel.result_count(), &mut self.results_picker)
|
||||
}
|
||||
Mode::RemoteControl | Mode::SendToChannel => {
|
||||
(self.remote_control.total_count(), &mut self.rc_picker)
|
||||
}
|
||||
Mode::RemoteControl | Mode::SendToChannel => (
|
||||
self.remote_control.as_ref().unwrap().total_count(),
|
||||
&mut self.rc_picker,
|
||||
),
|
||||
};
|
||||
if result_count == 0 {
|
||||
return;
|
||||
@ -236,9 +247,10 @@ impl Television {
|
||||
Mode::Channel => {
|
||||
(self.channel.result_count(), &mut self.results_picker)
|
||||
}
|
||||
Mode::RemoteControl | Mode::SendToChannel => {
|
||||
(self.remote_control.total_count(), &mut self.rc_picker)
|
||||
}
|
||||
Mode::RemoteControl | Mode::SendToChannel => (
|
||||
self.remote_control.as_ref().unwrap().total_count(),
|
||||
&mut self.rc_picker,
|
||||
),
|
||||
};
|
||||
if result_count == 0 {
|
||||
return;
|
||||
@ -368,18 +380,20 @@ impl Television {
|
||||
|
||||
pub fn update_rc_picker_state(&mut self) {
|
||||
if self.rc_picker.selected().is_none()
|
||||
&& self.remote_control.result_count() > 0
|
||||
&& self.remote_control.as_ref().unwrap().result_count() > 0
|
||||
{
|
||||
self.rc_picker.select(Some(0));
|
||||
self.rc_picker.relative_select(Some(0));
|
||||
}
|
||||
|
||||
self.rc_picker.entries = self.remote_control.results(
|
||||
self.rc_picker.entries =
|
||||
self.remote_control.as_mut().unwrap().results(
|
||||
// this'll be more than the actual rc height but it's fine
|
||||
self.ui_state.layout.results.height.into(),
|
||||
u32::try_from(self.rc_picker.offset()).unwrap(),
|
||||
);
|
||||
self.rc_picker.total_items = self.remote_control.total_count();
|
||||
self.rc_picker.total_items =
|
||||
self.remote_control.as_ref().unwrap().total_count();
|
||||
}
|
||||
|
||||
pub fn handle_input_action(&mut self, action: &Action) {
|
||||
@ -408,6 +422,9 @@ impl Television {
|
||||
}
|
||||
|
||||
pub fn handle_toggle_rc(&mut self) {
|
||||
if self.remote_control.is_none() {
|
||||
return;
|
||||
}
|
||||
match self.mode {
|
||||
Mode::Channel => {
|
||||
self.mode = Mode::RemoteControl;
|
||||
@ -417,7 +434,7 @@ impl Television {
|
||||
// this resets the RC picker
|
||||
self.reset_picker_input();
|
||||
self.init_remote_control();
|
||||
self.remote_control.find(EMPTY_STRING);
|
||||
self.remote_control.as_mut().unwrap().find(EMPTY_STRING);
|
||||
self.reset_picker_selection();
|
||||
self.mode = Mode::Channel;
|
||||
}
|
||||
@ -426,16 +443,19 @@ impl Television {
|
||||
}
|
||||
|
||||
pub fn handle_toggle_send_to_channel(&mut self) {
|
||||
if self.remote_control.is_none() {
|
||||
return;
|
||||
}
|
||||
match self.mode {
|
||||
Mode::Channel | Mode::RemoteControl => {
|
||||
self.mode = Mode::SendToChannel;
|
||||
self.remote_control = TelevisionChannel::RemoteControl(
|
||||
self.remote_control = Some(TelevisionChannel::RemoteControl(
|
||||
RemoteControl::with_transitions_from(&self.channel),
|
||||
);
|
||||
));
|
||||
}
|
||||
Mode::SendToChannel => {
|
||||
self.reset_picker_input();
|
||||
self.remote_control.find(EMPTY_STRING);
|
||||
self.remote_control.as_mut().unwrap().find(EMPTY_STRING);
|
||||
self.reset_picker_selection();
|
||||
self.mode = Mode::Channel;
|
||||
}
|
||||
@ -462,12 +482,15 @@ impl Television {
|
||||
}
|
||||
Mode::RemoteControl => {
|
||||
if let Some(entry) = self.get_selected_entry(None) {
|
||||
let new_channel =
|
||||
self.remote_control.zap(entry.name.as_str())?;
|
||||
let new_channel = self
|
||||
.remote_control
|
||||
.as_ref()
|
||||
.unwrap()
|
||||
.zap(entry.name.as_str())?;
|
||||
// this resets the RC picker
|
||||
self.reset_picker_selection();
|
||||
self.reset_picker_input();
|
||||
self.remote_control.find(EMPTY_STRING);
|
||||
self.remote_control.as_mut().unwrap().find(EMPTY_STRING);
|
||||
self.mode = Mode::Channel;
|
||||
self.change_channel(new_channel);
|
||||
}
|
||||
@ -479,7 +502,7 @@ impl Television {
|
||||
.transition_to(entry.name.as_str().try_into()?);
|
||||
self.reset_picker_selection();
|
||||
self.reset_picker_input();
|
||||
self.remote_control.find(EMPTY_STRING);
|
||||
self.remote_control.as_mut().unwrap().find(EMPTY_STRING);
|
||||
self.mode = Mode::Channel;
|
||||
self.change_channel(new_channel);
|
||||
}
|
||||
@ -589,7 +612,9 @@ impl Television {
|
||||
|
||||
self.update_results_picker_state();
|
||||
|
||||
if self.remote_control.is_some() {
|
||||
self.update_rc_picker_state();
|
||||
}
|
||||
|
||||
let selected_entry = self
|
||||
.get_selected_entry(Some(Mode::Channel))
|
||||
|
@ -39,7 +39,7 @@ fn setup_app(
|
||||
config.application.tick_rate = 100.0;
|
||||
let input = None;
|
||||
|
||||
let mut app = App::new(chan, config, input, select_1);
|
||||
let mut app = App::new(chan, config, input, select_1, false);
|
||||
|
||||
// retrieve the app's action channel handle in order to send a quit action
|
||||
let tx = app.action_tx.clone();
|
||||
|
Loading…
x
Reference in New Issue
Block a user