shell_scene/engine/
record.rs1use crate::util::{deps, fsx, net, proc};
2use clap::ArgMatches;
3use std::path::{Path, PathBuf};
4
5pub fn run_record(m: &ArgMatches) -> i32 {
6 let session = m.get_one::<String>("session").unwrap().to_owned();
8 let cols = *m.get_one::<u32>("cols").unwrap();
9 let rows = *m.get_one::<u32>("rows").unwrap();
10 let port_start = *m.get_one::<u16>("port").unwrap();
11 let font_size = *m.get_one::<u32>("font_size").unwrap();
12 let mut out = m.get_one::<PathBuf>("out").cloned();
13 let mut workdir = m.get_one::<PathBuf>("workdir").cloned();
14 let kill = *m.get_one::<bool>("kill_on_detach").unwrap_or(&false);
15 deps::require_cmds(&["ttyd", "tmux", "asciinema"]);
17 deps::warn_optionals();
18
19 let home = fsx::home_dir();
21 if workdir.is_none() {
22 workdir = Some(home.clone());
23 }
24 if out.is_none() {
25 out = Some(home.join("casts").join(format!(
26 "{}-{}.cast",
27 session,
28 fsx::now_yyyymmdd_hhmmss()
29 )));
30 }
31
32 let out = out.unwrap();
33 let workdir = workdir.unwrap();
34
35 fsx::validate_workdir(&workdir);
37 fsx::ensure_writable_dir(out.parent().unwrap_or_else(|| Path::new(".")));
38
39 let port = net::find_free_port(port_start);
40
41 let exe = std::env::current_exe().expect("failed to get current exe path");
42 let mut cmd_and_args = vec![
43 exe.to_string_lossy().to_string(),
44 "record-hook".to_string(),
45 "--child".to_string(),
46 "--session".to_string(),
47 session.clone(),
48 "--cols".to_string(),
49 cols.to_string(),
50 "--rows".to_string(),
51 rows.to_string(),
52 "--out".to_string(),
53 out.to_string_lossy().to_string(),
54 "--workdir".to_string(),
55 workdir.to_string_lossy().to_string(),
56 ];
57 if kill {
58 cmd_and_args.push("--kill-on-detach".into());
59 }
60
61 let envs = vec![
62 ("SESSION", session.clone()),
63 ("TMUX_COLS", cols.to_string()),
64 ("TMUX_ROWS", rows.to_string()),
65 ("ASCII_OUT", out.to_string_lossy().to_string()),
66 (
67 "TMUX_KILL_ON_DETACH",
68 if kill {
69 "true".to_string()
70 } else {
71 "false".to_string()
72 },
73 ),
74 ];
75
76 proc::spawn_ttyd_and_wait(port, font_size, &session, &envs, &cmd_and_args)
77}
78
79pub fn run_record_hook(m: &ArgMatches) -> i32 {
80 let _child = m.get_flag("child");
81 let session = m.get_one::<String>("session").unwrap().to_owned();
82 let cols = *m.get_one::<u32>("cols").unwrap();
83 let rows = *m.get_one::<u32>("rows").unwrap();
84 let mut out = m.get_one::<PathBuf>("out").cloned();
85 let mut workdir = m.get_one::<PathBuf>("workdir").cloned();
86 let kill = m.get_flag("kill_on_detach");
87
88 let home = fsx::home_dir();
89 if workdir.is_none() {
90 workdir = Some(home.clone());
91 }
92 if out.is_none() {
93 out = Some(home.join("casts").join(format!(
94 "{}-{}.cast",
95 session,
96 fsx::now_yyyymmdd_hhmmss()
97 )));
98 }
99
100 let out = out.unwrap();
101 let workdir = workdir.unwrap();
102
103 fsx::validate_workdir(&workdir);
104 fsx::ensure_writable_dir(out.parent().unwrap_or_else(|| Path::new(".")));
105
106 proc::record_flow(&session, cols, rows, &out, &workdir, kill)
107}