fix: negotiate modified Return keyboard reporting
This commit is contained in:
@@ -73,6 +73,8 @@ Two or more checked videos launch `terebi --new-instance --queue-file '/private/
|
|||||||
|
|
||||||
**Ctrl+Return** (`video.enqueue`) sends the same checked rows, or the hovered row when none are checked, to a running Terebi queue without replacing its current playback. The terminal must transmit the modified Return, or you can rebind the action. Enqueue always uses `terebi --enqueue --queue-file '/private/session/queue.json'`, even for one video, preserving independent per-item progress. If Terebi is not running, it starts with that queue. Plain Return still opens a new instance. These shortcuts do nothing on Miruro catalog titles or saved shows and do not submit text inputs.
|
**Ctrl+Return** (`video.enqueue`) sends the same checked rows, or the hovered row when none are checked, to a running Terebi queue without replacing its current playback. The terminal must transmit the modified Return, or you can rebind the action. Enqueue always uses `terebi --enqueue --queue-file '/private/session/queue.json'`, even for one video, preserving independent per-item progress. If Terebi is not running, it starts with that queue. Plain Return still opens a new instance. These shortcuts do nothing on Miruro catalog titles or saved shows and do not submit text inputs.
|
||||||
|
|
||||||
|
Tubular requests the Kitty keyboard protocol's escape-code disambiguation for its entire terminal session and restores the previous mode on exit. Supporting terminals can then distinguish Ctrl+Return from plain Return. A terminal or multiplexer that does not support/forward this protocol may still send identical bytes for both; Tubular cannot distinguish them. In that case, configure another key, for example `[keys.video]` with `enqueue = "alt+e"`.
|
||||||
|
|
||||||
### Miruro browser
|
### Miruro browser
|
||||||
|
|
||||||
Choose **Miruro** at startup or use `--miruro` to start directly. Its interface is **catalog → series → episodes**, with a separate saved-show library organized by overlapping category tags, without YouTube's Search/Feed tabs or channel controls.
|
Choose **Miruro** at startup or use `--miruro` to start directly. Its interface is **catalog → series → episodes**, with a separate saved-show library organized by overlapping category tags, without YouTube's Search/Feed tabs or channel controls.
|
||||||
|
|||||||
@@ -128,7 +128,8 @@ The complete request is rejected on an identity already in the current queue, a
|
|||||||
### Enqueue verification
|
### Enqueue verification
|
||||||
|
|
||||||
- Tubular: `cargo fmt --all`, `cargo test --locked` (**233 passed**), `cargo build --locked` and built `--help`; Rust launcher diagnostics were clean.
|
- Tubular: `cargo fmt --all`, `cargo test --locked` (**233 passed**), `cargo build --locked` and built `--help`; Rust launcher diagnostics were clean.
|
||||||
- Actual YouTube and Miruro terminal interfaces: reverse-checked rows produced display-ordered enqueue manifests, cleared checks fell back to the hovered row, Ctrl/Super+Return and an F12 override worked, and plain Return still used `--new-instance --url`. Six handoffs used private `0600` manifests in `0700` session directories with distinct report destinations. The capture launcher did not run Terebi.
|
- Actual YouTube and Miruro terminal interfaces with injected modified-key sequences: reverse-checked rows produced display-ordered enqueue manifests, cleared checks fell back to the hovered row, Ctrl/Super+Return and an F12 override worked, and plain Return still used `--new-instance --url`. Six handoffs used private `0600` manifests in `0700` session directories with distinct report destinations. The capture launcher did not run Terebi, and injecting already-encoded modified keys did not verify terminal protocol negotiation.
|
||||||
- Terebi: `check-cli`, `check-queue`, `check-reporting` and `make all` passed. A regression check first failed on rebinding the original single-video identity and passed after binding it independently of appended reports.
|
- Terebi: `check-cli`, `check-queue`, `check-reporting` and `make all` passed. A regression check first failed on rebinding the original single-video identity and passed after binding it independently of appended reports.
|
||||||
- Headless native enqueue smoke with local video-only HLS passed: repeated delivery while paused/playing, unchanged current selection/revision, lazy mixed-provider append, natural-end advance, navigation/revisits, atomic rejection/rollback, isolated original/appended reports and empty-player startup.
|
- Headless native enqueue smoke with local video-only HLS passed: repeated delivery while paused/playing, unchanged current selection/revision, lazy mixed-provider append, natural-end advance, navigation/revisits, atomic rejection/rollback, isolated original/appended reports and empty-player startup.
|
||||||
- Full `make check-resolved` stopped in the pre-existing mixed-queue natural-end scenario at `Could not start Core Audio (560227702)` before reaching enqueue. No full A/V-suite pass is claimed. No packaged-GUI/LaunchServices smoke or visual-layout confirmation was performed; the app was built, not installed. Temporary terminal/server fixtures were removed.
|
- Full `make check-resolved` stopped in the pre-existing mixed-queue natural-end scenario at `Could not start Core Audio (560227702)` before reaching enqueue. No full A/V-suite pass is claimed. No packaged-GUI/LaunchServices smoke or visual-layout confirmation was performed; the app was built, not installed. Temporary terminal/server fixtures were removed.
|
||||||
|
- Modified-Return correction: a protocol-aware PTY driver reproduced Ctrl+Return opening a new instance when startup did not request disambiguation. After adding a session-scoped Kitty keyboard protocol push/pop, the same actual TUI driver observed Ctrl+Return using `--enqueue`, plain Return using `--new-instance`, and keyboard-mode restoration on exit. `cargo test --locked` remained **233 passed** and the build passed. This emulates a supporting terminal; it does not prove support in the user's terminal/multiplexer. Legacy identical Return bytes require a different binding.
|
||||||
|
|||||||
@@ -3854,6 +3854,7 @@ fn main() -> io::Result<()> {
|
|||||||
let config_path = config::config_path()?;
|
let config_path = config::config_path()?;
|
||||||
let config = config::load(&config_path)?;
|
let config = config::load(&config_path)?;
|
||||||
ratatui::run(|terminal| {
|
ratatui::run(|terminal| {
|
||||||
|
let _keyboard = ui::KeyboardProtocol::enable()?;
|
||||||
if !options.miruro {
|
if !options.miruro {
|
||||||
let Some(miruro) = choose_provider(terminal, &config.keys, None)? else {
|
let Some(miruro) = choose_provider(terminal, &config.keys, None)? else {
|
||||||
return Ok(());
|
return Ok(());
|
||||||
|
|||||||
@@ -2,7 +2,13 @@ use std::time::Duration;
|
|||||||
|
|
||||||
use ratatui::{
|
use ratatui::{
|
||||||
Frame,
|
Frame,
|
||||||
crossterm::{clipboard::CopyToClipboard, execute},
|
crossterm::{
|
||||||
|
clipboard::CopyToClipboard,
|
||||||
|
event::{
|
||||||
|
KeyboardEnhancementFlags, PopKeyboardEnhancementFlags, PushKeyboardEnhancementFlags,
|
||||||
|
},
|
||||||
|
execute,
|
||||||
|
},
|
||||||
layout::{Constraint, Layout, Rect},
|
layout::{Constraint, Layout, Rect},
|
||||||
style::{Color, Style},
|
style::{Color, Style},
|
||||||
text::{Line, Span},
|
text::{Line, Span},
|
||||||
@@ -13,6 +19,25 @@ pub const ACCENT: Style = Style::new().fg(Color::Cyan);
|
|||||||
pub const SELECTED: Style = Style::new().fg(Color::Black).bg(Color::Cyan);
|
pub const SELECTED: Style = Style::new().fg(Color::Black).bg(Color::Cyan);
|
||||||
pub const SELECTION_MARKER: &str = "> ";
|
pub const SELECTION_MARKER: &str = "> ";
|
||||||
|
|
||||||
|
// Keep modified Return distinct from Return on terminals supporting the Kitty protocol.
|
||||||
|
pub struct KeyboardProtocol;
|
||||||
|
|
||||||
|
impl KeyboardProtocol {
|
||||||
|
pub fn enable() -> std::io::Result<Self> {
|
||||||
|
execute!(
|
||||||
|
std::io::stdout(),
|
||||||
|
PushKeyboardEnhancementFlags(KeyboardEnhancementFlags::DISAMBIGUATE_ESCAPE_CODES)
|
||||||
|
)?;
|
||||||
|
Ok(Self)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Drop for KeyboardProtocol {
|
||||||
|
fn drop(&mut self) {
|
||||||
|
let _ = execute!(std::io::stdout(), PopKeyboardEnhancementFlags);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn copy_video_url(id: &str) -> String {
|
pub fn copy_video_url(id: &str) -> String {
|
||||||
let result = crate::youtube::video_url(id)
|
let result = crate::youtube::video_url(id)
|
||||||
.and_then(|url| execute!(std::io::stdout(), CopyToClipboard::to_clipboard_from(url)));
|
.and_then(|url| execute!(std::io::stdout(), CopyToClipboard::to_clipboard_from(url)));
|
||||||
|
|||||||
Reference in New Issue
Block a user