Implement text output for rec command

This commit is contained in:
Marcin Kulik
2024-01-24 21:19:10 +01:00
parent 1534d90c88
commit 050b31d707
6 changed files with 126 additions and 1 deletions

25
Cargo.lock generated
View File

@@ -87,6 +87,7 @@ name = "asciinema"
version = "3.0.0-beta.1"
dependencies = [
"anyhow",
"avt",
"clap",
"config",
"nix",
@@ -132,6 +133,15 @@ version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa"
[[package]]
name = "avt"
version = "0.8.3"
source = "git+https://github.com/asciinema/avt?tag=v0.8.3#28aed2b5a65a4ff07344fd6bc51b8ccb8542389c"
dependencies = [
"rgb",
"serde",
]
[[package]]
name = "backtrace"
version = "0.3.69"
@@ -171,6 +181,12 @@ version = "3.14.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7f30e7476521f6f8af1a1c4c0b8cc94f0bee37d91763d0ca2665f299b6cd8aec"
[[package]]
name = "bytemuck"
version = "1.14.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "374d28ec25809ee0e23827c2ab573d729e293f281dfe393500e7ad618baa61c6"
[[package]]
name = "byteorder"
version = "1.5.0"
@@ -1255,6 +1271,15 @@ dependencies = [
"winreg",
]
[[package]]
name = "rgb"
version = "0.8.37"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "05aaa8004b64fd573fc9d002f4e632d51ad4f026c2b5ba95fcb6c2f32c2c47d8"
dependencies = [
"bytemuck",
]
[[package]]
name = "ring"
version = "0.17.7"

View File

@@ -25,3 +25,4 @@ config = { version = "0.13.4", default-features = false, features = ["toml", "in
which = "5.0.0"
tempfile = "3.9.0"
scraper = { version = "0.15.0", default-features = false }
avt = { git = "https://github.com/asciinema/avt", tag = "v0.8.3" }

View File

@@ -68,6 +68,7 @@ pub struct Cli {
enum Format {
Asciicast,
Raw,
Txt,
}
#[derive(Clone, Debug)]
@@ -84,7 +85,6 @@ impl Cli {
let keys = get_key_bindings(config)?;
let notifier = get_notifier(config);
let record_input = self.input || config.cmd_rec_input();
let mut recorder = recorder::Recorder::new(output, record_input, keys, notifier);
let exec_command = build_exec_command(command.as_ref().cloned());
let exec_extra_env = build_exec_extra_env();
let tty_size = self.get_tty_size();
@@ -103,6 +103,8 @@ impl Cli {
Box::new(tty::NullTty::open()?)
};
let mut recorder = recorder::Recorder::new(output, record_input, keys, notifier);
pty::exec(
&exec_command,
&exec_extra_env,
@@ -179,6 +181,7 @@ impl Cli {
}
Format::Raw => Ok(Box::new(output::Raw::new(file, append))),
Format::Txt => Ok(Box::new(output::Txt::new(file))),
}
}

View File

@@ -1,6 +1,8 @@
mod asciicast;
mod raw;
mod txt;
pub use asciicast::Asciicast;
pub use asciicast::Metadata;
pub use raw::Raw;
pub use txt::Txt;

88
src/output/txt.rs Normal file
View File

@@ -0,0 +1,88 @@
use crate::recorder;
use crate::tty;
use std::io::{self, Write};
pub struct Txt<W> {
writer: W,
vt: Option<avt::Vt>,
}
impl<W> Txt<W> {
pub fn new(writer: W) -> Self {
Txt { writer, vt: None }
}
}
impl<W: Write> recorder::Output for Txt<W> {
fn start(&mut self, _timestamp: u64, tty_size: &tty::TtySize) -> io::Result<()> {
let (cols, rows) = (*tty_size).into();
let vt = avt::Vt::builder()
.size(cols as usize, rows as usize)
.resizable(true)
.build();
self.vt = Some(vt);
Ok(())
}
fn output(&mut self, _time: u64, data: &[u8]) -> io::Result<()> {
let data = String::from_utf8_lossy(data).to_string();
self.vt.as_mut().unwrap().feed_str(&data);
Ok(())
}
fn input(&mut self, _time: u64, _data: &[u8]) -> io::Result<()> {
Ok(())
}
fn resize(&mut self, _time: u64, (cols, rows): (u16, u16)) -> io::Result<()> {
self.vt
.as_mut()
.unwrap()
.feed_str(&format!("\x1b[8;{rows};{cols}t"));
Ok(())
}
fn marker(&mut self, _time: u64) -> io::Result<()> {
Ok(())
}
fn finish(&mut self) -> io::Result<()> {
let mut text = self.vt.as_ref().unwrap().text();
while !text.is_empty() && text[text.len() - 1].is_empty() {
text.truncate(text.len() - 1);
}
for line in text {
self.writer.write_all(line.as_bytes())?;
self.writer.write_all(b"\n")?;
}
Ok(())
}
}
#[cfg(test)]
mod test {
use super::Txt;
use crate::recorder::Output;
use crate::tty::TtySize;
#[test]
fn x() {
let mut output: Vec<u8> = Vec::new();
let mut txt = Txt::new(&mut output);
txt.start(1706111685, &TtySize(3, 1)).unwrap();
txt.output(0, b"he\x1b[1mllo\r\n").unwrap();
txt.output(1, b"world\r\n").unwrap();
txt.finish().unwrap();
assert_eq!(output, b"hello\nworld\n");
}
}

View File

@@ -26,6 +26,10 @@ pub trait Output {
fn input(&mut self, time: u64, data: &[u8]) -> io::Result<()>;
fn resize(&mut self, time: u64, size: (u16, u16)) -> io::Result<()>;
fn marker(&mut self, time: u64) -> io::Result<()>;
fn finish(&mut self) -> io::Result<()> {
Ok(())
}
}
enum Message {
@@ -120,6 +124,8 @@ impl pty::Recorder for Recorder {
}
}
}
let _ = output.finish();
});
self.handle = Some(JoinHandle(Some(handle)));