mirror of
https://github.com/asciinema/asciinema.git
synced 2025-12-16 11:48:13 +01:00
Implement text output for rec command
This commit is contained in:
25
Cargo.lock
generated
25
Cargo.lock
generated
@@ -87,6 +87,7 @@ name = "asciinema"
|
|||||||
version = "3.0.0-beta.1"
|
version = "3.0.0-beta.1"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
|
"avt",
|
||||||
"clap",
|
"clap",
|
||||||
"config",
|
"config",
|
||||||
"nix",
|
"nix",
|
||||||
@@ -132,6 +133,15 @@ version = "1.1.0"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa"
|
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]]
|
[[package]]
|
||||||
name = "backtrace"
|
name = "backtrace"
|
||||||
version = "0.3.69"
|
version = "0.3.69"
|
||||||
@@ -171,6 +181,12 @@ version = "3.14.0"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "7f30e7476521f6f8af1a1c4c0b8cc94f0bee37d91763d0ca2665f299b6cd8aec"
|
checksum = "7f30e7476521f6f8af1a1c4c0b8cc94f0bee37d91763d0ca2665f299b6cd8aec"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "bytemuck"
|
||||||
|
version = "1.14.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "374d28ec25809ee0e23827c2ab573d729e293f281dfe393500e7ad618baa61c6"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "byteorder"
|
name = "byteorder"
|
||||||
version = "1.5.0"
|
version = "1.5.0"
|
||||||
@@ -1255,6 +1271,15 @@ dependencies = [
|
|||||||
"winreg",
|
"winreg",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "rgb"
|
||||||
|
version = "0.8.37"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "05aaa8004b64fd573fc9d002f4e632d51ad4f026c2b5ba95fcb6c2f32c2c47d8"
|
||||||
|
dependencies = [
|
||||||
|
"bytemuck",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "ring"
|
name = "ring"
|
||||||
version = "0.17.7"
|
version = "0.17.7"
|
||||||
|
|||||||
@@ -25,3 +25,4 @@ config = { version = "0.13.4", default-features = false, features = ["toml", "in
|
|||||||
which = "5.0.0"
|
which = "5.0.0"
|
||||||
tempfile = "3.9.0"
|
tempfile = "3.9.0"
|
||||||
scraper = { version = "0.15.0", default-features = false }
|
scraper = { version = "0.15.0", default-features = false }
|
||||||
|
avt = { git = "https://github.com/asciinema/avt", tag = "v0.8.3" }
|
||||||
|
|||||||
@@ -68,6 +68,7 @@ pub struct Cli {
|
|||||||
enum Format {
|
enum Format {
|
||||||
Asciicast,
|
Asciicast,
|
||||||
Raw,
|
Raw,
|
||||||
|
Txt,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
@@ -84,7 +85,6 @@ impl Cli {
|
|||||||
let keys = get_key_bindings(config)?;
|
let keys = get_key_bindings(config)?;
|
||||||
let notifier = get_notifier(config);
|
let notifier = get_notifier(config);
|
||||||
let record_input = self.input || config.cmd_rec_input();
|
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_command = build_exec_command(command.as_ref().cloned());
|
||||||
let exec_extra_env = build_exec_extra_env();
|
let exec_extra_env = build_exec_extra_env();
|
||||||
let tty_size = self.get_tty_size();
|
let tty_size = self.get_tty_size();
|
||||||
@@ -103,6 +103,8 @@ impl Cli {
|
|||||||
Box::new(tty::NullTty::open()?)
|
Box::new(tty::NullTty::open()?)
|
||||||
};
|
};
|
||||||
|
|
||||||
|
let mut recorder = recorder::Recorder::new(output, record_input, keys, notifier);
|
||||||
|
|
||||||
pty::exec(
|
pty::exec(
|
||||||
&exec_command,
|
&exec_command,
|
||||||
&exec_extra_env,
|
&exec_extra_env,
|
||||||
@@ -179,6 +181,7 @@ impl Cli {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Format::Raw => Ok(Box::new(output::Raw::new(file, append))),
|
Format::Raw => Ok(Box::new(output::Raw::new(file, append))),
|
||||||
|
Format::Txt => Ok(Box::new(output::Txt::new(file))),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,8 @@
|
|||||||
mod asciicast;
|
mod asciicast;
|
||||||
mod raw;
|
mod raw;
|
||||||
|
mod txt;
|
||||||
|
|
||||||
pub use asciicast::Asciicast;
|
pub use asciicast::Asciicast;
|
||||||
pub use asciicast::Metadata;
|
pub use asciicast::Metadata;
|
||||||
pub use raw::Raw;
|
pub use raw::Raw;
|
||||||
|
pub use txt::Txt;
|
||||||
|
|||||||
88
src/output/txt.rs
Normal file
88
src/output/txt.rs
Normal 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");
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -26,6 +26,10 @@ pub trait Output {
|
|||||||
fn input(&mut self, time: u64, data: &[u8]) -> io::Result<()>;
|
fn input(&mut self, time: u64, data: &[u8]) -> io::Result<()>;
|
||||||
fn resize(&mut self, time: u64, size: (u16, u16)) -> io::Result<()>;
|
fn resize(&mut self, time: u64, size: (u16, u16)) -> io::Result<()>;
|
||||||
fn marker(&mut self, time: u64) -> io::Result<()>;
|
fn marker(&mut self, time: u64) -> io::Result<()>;
|
||||||
|
|
||||||
|
fn finish(&mut self) -> io::Result<()> {
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
enum Message {
|
enum Message {
|
||||||
@@ -120,6 +124,8 @@ impl pty::Recorder for Recorder {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let _ = output.finish();
|
||||||
});
|
});
|
||||||
|
|
||||||
self.handle = Some(JoinHandle(Some(handle)));
|
self.handle = Some(JoinHandle(Some(handle)));
|
||||||
|
|||||||
Reference in New Issue
Block a user