shell_scene/engine/
record.rs

1use crate::util::{deps, fsx, net, proc};
2use clap::ArgMatches;
3use std::path::{Path, PathBuf};
4
5pub fn run_record(m: &ArgMatches) -> i32 {
6    // Parse
7    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
16    deps::require_cmds(&["ttyd", "tmux", "asciinema"]);
17    deps::warn_optionals();
18
19    // defaults
20    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    // validations
36    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}