Skip to main content

vipe_rs/
lib.rs

1use std::env;
2use std::fs::{self};
3use std::io::{self, Write};
4use std::process::{Command, Stdio};
5use tempfile::NamedTempFile;
6
7// For checking if stdin is a TTY (Terminal)
8use atty::is as is_atty;
9
10// Unix-specific imports for handling raw file descriptors
11
12/// The version of the vipe utility.
13const VERSION: &str = "1.0.0";
14
15pub fn run() -> Result<(), Box<dyn std::error::Error>> {
16    let args: Vec<String> = env::args().collect();
17    if args.len() > 1 {
18        match args[1].as_str() {
19            "-a" => {
20                // Print about information and exit successfully.
21                println!("about:");
22                println!("       https://github.com/madx/moreutils.git");
23                println!("       https://raw.githubusercontent.com/madx/moreutils/refs/heads/master/vipe");
24                println!("       https://github.com/juliangruber/vipe.git");
25                println!("       https://raw.githubusercontent.com/juliangruber/vipe/refs/heads/master/vipe.sh");
26                return Ok(());
27            }
28            "--about" => {
29                // Print about information and exit successfully.
30                println!("about:");
31                println!("       https://github.com/madx/moreutils.git");
32                println!("       https://raw.githubusercontent.com/madx/moreutils/refs/heads/master/vipe");
33                println!("       https://github.com/juliangruber/vipe.git");
34                println!("       https://raw.githubusercontent.com/juliangruber/vipe/refs/heads/master/vipe.sh");
35                return Ok(());
36            }
37            "-h" => {
38                // Print usage information and exit successfully.
39                println!("usage: vipe [-ahV]");
40                return Ok(());
41            }
42            "--help" => {
43                // Print usage information and exit successfully.
44                println!("usage: vipe [-ahV]");
45                return Ok(());
46            }
47            "-V" => {
48                // Print the version and exit successfully.
49                println!("{}", VERSION);
50                return Ok(());
51            }
52            "--version" => {
53                // Print the version and exit successfully.
54                println!("{}", VERSION);
55                return Ok(());
56            }
57            _ => {
58                // Handle unknown options, print usage, and exit with an error.
59                eprintln!("unknown option: \"{}\"", args[1]);
60                eprintln!("usage: vipe [-hV]");
61                std::process::exit(1);
62            }
63        }
64    }
65
66    let editor = env::var("EDITOR").unwrap_or_else(|_| {
67        if cfg!(windows) {
68            "notepad.exe".to_string()
69        } else {
70            "vi".to_string()
71        }
72    });
73
74    let mut temp_file = NamedTempFile::new()?;
75    let temp_path = temp_file.path().to_owned();
76    if !is_atty(atty::Stream::Stdin) {
77        let mut stdin = io::stdin();
78        io::copy(&mut stdin, &mut temp_file)?;
79    }
80
81    temp_file.flush()?;
82
83    let status = Command::new(&editor)
84        .arg(&temp_path)
85        .stdin(Stdio::inherit())
86        .stdout(Stdio::inherit())
87        .stderr(Stdio::inherit())
88        .status()?;
89
90    if !status.success() {
91        eprintln!("Editor exited with non-zero status: {:?}", status.code());
92        std::process::exit(status.code().unwrap_or(1));
93    }
94
95    let content = fs::read_to_string(&temp_path)?;
96
97    print!("{}", content);
98
99    Ok(())
100}