edit-0.1.5/.cargo_vcs_info.json0000644000000001360000000000100117640ustar { "git": { "sha1": "4a64d10303e75b7240ee970f9728e67ca0d84264" }, "path_in_vcs": "" }edit-0.1.5/.gitignore000064400000000000000000000000361046102023000125430ustar 00000000000000/target **/*.rs.bk Cargo.lock edit-0.1.5/Cargo.lock0000644000000127710000000000100077470ustar # This file is automatically @generated by Cargo. # It is not intended for manual editing. version = 3 [[package]] name = "bitflags" version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693" [[package]] name = "cfg-if" version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" [[package]] name = "edit" version = "0.1.5" dependencies = [ "shell-words", "tempfile", "which", ] [[package]] name = "getrandom" version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c9495705279e7140bf035dde1f6e750c162df8b625267cd52cc44e0b156732c8" dependencies = [ "cfg-if", "libc", "wasi", ] [[package]] name = "libc" version = "0.2.86" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b7282d924be3275cec7f6756ff4121987bc6481325397dde6ba3e7802b1a8b1c" [[package]] name = "ppv-lite86" version = "0.2.10" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ac74c624d6b2d21f425f752262f42188365d7b8ff1aff74c82e45136510a4857" [[package]] name = "proc-macro2" version = "1.0.24" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1e0704ee1a7e00d7bb417d0770ea303c1bccbabf0ef1667dae92b5967f5f8a71" dependencies = [ "unicode-xid", ] [[package]] name = "quote" version = "1.0.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c3d0b9745dc2debf507c8422de05d7226cc1f0644216dfdfead988f9b1ab32a7" dependencies = [ "proc-macro2", ] [[package]] name = "rand" version = "0.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0ef9e7e66b4468674bfcb0c81af8b7fa0bb154fa9f28eb840da5c447baeb8d7e" dependencies = [ "libc", "rand_chacha", "rand_core", "rand_hc", ] [[package]] name = "rand_chacha" version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e12735cf05c9e10bf21534da50a147b924d555dc7a547c42e6bb2d5b6017ae0d" dependencies = [ "ppv-lite86", "rand_core", ] [[package]] name = "rand_core" version = "0.6.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "34cf66eb183df1c5876e2dcf6b13d57340741e8dc255b48e40a26de954d06ae7" dependencies = [ "getrandom", ] [[package]] name = "rand_hc" version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3190ef7066a446f2e7f42e239d161e905420ccab01eb967c9eb27d21b2322a73" dependencies = [ "rand_core", ] [[package]] name = "redox_syscall" version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "94341e4e44e24f6b591b59e47a8a027df12e008d73fd5672dbea9cc22f4507d9" dependencies = [ "bitflags", ] [[package]] name = "remove_dir_all" version = "0.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3acd125665422973a33ac9d3dd2df85edad0f4ae9b00dafb1a05e43a9f5ef8e7" dependencies = [ "winapi", ] [[package]] name = "shell-words" version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "24188a676b6ae68c3b2cb3a01be17fbf7240ce009799bb56d5b1409051e78fde" [[package]] name = "syn" version = "1.0.60" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c700597eca8a5a762beb35753ef6b94df201c81cca676604f547495a0d7f0081" dependencies = [ "proc-macro2", "quote", "unicode-xid", ] [[package]] name = "tempfile" version = "3.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dac1c663cfc93810f88aed9b8941d48cabf856a1b111c29a40439018d870eb22" dependencies = [ "cfg-if", "libc", "rand", "redox_syscall", "remove_dir_all", "winapi", ] [[package]] name = "thiserror" version = "1.0.24" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e0f4a65597094d4483ddaed134f409b2cb7c1beccf25201a9f73c719254fa98e" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" version = "1.0.24" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7765189610d8241a44529806d6fd1f2e0a08734313a35d5b3a556f92b381f3c0" dependencies = [ "proc-macro2", "quote", "syn", ] [[package]] name = "unicode-xid" version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f7fe0bb3479651439c9112f72b6c505038574c9fbb575ed1bf3b797fa39dd564" [[package]] name = "wasi" version = "0.10.2+wasi-snapshot-preview1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fd6fbd9a79829dd1ad0cc20627bf1ed606756a7f77edff7b66b7064f9cb327c6" [[package]] name = "which" version = "4.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "87c14ef7e1b8b8ecfc75d5eca37949410046e66f15d185c01d70824f1f8111ef" dependencies = [ "libc", "thiserror", ] [[package]] name = "winapi" version = "0.3.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" dependencies = [ "winapi-i686-pc-windows-gnu", "winapi-x86_64-pc-windows-gnu", ] [[package]] name = "winapi-i686-pc-windows-gnu" version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" [[package]] name = "winapi-x86_64-pc-windows-gnu" version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" edit-0.1.5/Cargo.toml0000644000000022550000000000100077660ustar # THIS FILE IS AUTOMATICALLY GENERATED BY CARGO # # When uploading crates to the registry Cargo will automatically # "normalize" Cargo.toml files for maximal compatibility # with all versions of Cargo and also rewrite `path` dependencies # to registry (e.g., crates.io) dependencies. # # If you are reading this file be aware that the original Cargo.toml # will likely look very different (and much more reasonable). # See Cargo.toml.orig for the original contents. [package] edition = "2018" name = "edit" version = "0.1.5" authors = ["Milkey Mouse "] description = "Open a file in the default text editor" readme = "README.md" keywords = [ "editor", "edit", "editing", "cli", ] categories = [ "command-line-interface", "config", "text-processing", "text-editors", ] license = "CC0-1.0" repository = "https://github.com/milkey-mouse/edit" [lib] name = "edit" [dependencies.shell-words] version = "1.1.0" optional = true [dependencies.tempfile] version = "3.1.0" [dependencies.which] version = "4.0" optional = true default-features = false [features] better-path = ["which"] default = ["better-path"] quoted-env = ["shell-words"] edit-0.1.5/Cargo.toml.orig000064400000000000000000000012061046102023000134420ustar 00000000000000[package] name = "edit" description = "Open a file in the default text editor" authors = ["Milkey Mouse "] repository = "https://github.com/milkey-mouse/edit" keywords = ["editor", "edit", "editing", "cli"] categories = ["command-line-interface", "config", "text-processing", "text-editors"] license = "CC0-1.0" version = "0.1.5" edition = "2018" [lib] name = "edit" [features] default = ["better-path"] better-path = ["which"] quoted-env = ["shell-words"] [dependencies] shell-words = { version = "1.1.0", optional = true } tempfile = "3.1.0" which = { version = "4.0", default-features = false, optional = true } edit-0.1.5/LICENSE000064400000000000000000000146331046102023000115700ustar 00000000000000CC0 1.0 Universal Statement of Purpose The laws of most jurisdictions throughout the world automatically confer exclusive Copyright and Related Rights (defined below) upon the creator and subsequent owner(s) (each and all, an "owner") of an original work of authorship and/or a database (each, a "Work"). Certain owners wish to permanently relinquish those rights to a Work for the purpose of contributing to a commons of creative, cultural and scientific works ("Commons") that the public can reliably and without fear of later claims of infringement build upon, modify, incorporate in other works, reuse and redistribute as freely as possible in any form whatsoever and for any purposes, including without limitation commercial purposes. These owners may contribute to the Commons to promote the ideal of a free culture and the further production of creative, cultural and scientific works, or to gain reputation or greater distribution for their Work in part through the use and efforts of others. For these and/or other purposes and motivations, and without any expectation of additional consideration or compensation, the person associating CC0 with a Work (the "Affirmer"), to the extent that he or she is an owner of Copyright and Related Rights in the Work, voluntarily elects to apply CC0 to the Work and publicly distribute the Work under its terms, with knowledge of his or her Copyright and Related Rights in the Work and the meaning and intended legal effect of CC0 on those rights. 1. Copyright and Related Rights. A Work made available under CC0 may be protected by copyright and related or neighboring rights ("Copyright and Related Rights"). Copyright and Related Rights include, but are not limited to, the following: i. the right to reproduce, adapt, distribute, perform, display, communicate, and translate a Work; ii. moral rights retained by the original author(s) and/or performer(s); iii. publicity and privacy rights pertaining to a person's image or likeness depicted in a Work; iv. rights protecting against unfair competition in regards to a Work, subject to the limitations in paragraph 4(a), below; v. rights protecting the extraction, dissemination, use and reuse of data in a Work; vi. database rights (such as those arising under Directive 96/9/EC of the European Parliament and of the Council of 11 March 1996 on the legal protection of databases, and under any national implementation thereof, including any amended or successor version of such directive); and vii. other similar, equivalent or corresponding rights throughout the world based on applicable law or treaty, and any national implementations thereof. 2. Waiver. To the greatest extent permitted by, but not in contravention of, applicable law, Affirmer hereby overtly, fully, permanently, irrevocably and unconditionally waives, abandons, and surrenders all of Affirmer's Copyright and Related Rights and associated claims and causes of action, whether now known or unknown (including existing as well as future claims and causes of action), in the Work (i) in all territories worldwide, (ii) for the maximum duration provided by applicable law or treaty (including future time extensions), (iii) in any current or future medium and for any number of copies, and (iv) for any purpose whatsoever, including without limitation commercial, advertising or promotional purposes (the "Waiver"). Affirmer makes the Waiver for the benefit of each member of the public at large and to the detriment of Affirmer's heirs and successors, fully intending that such Waiver shall not be subject to revocation, rescission, cancellation, termination, or any other legal or equitable action to disrupt the quiet enjoyment of the Work by the public as contemplated by Affirmer's express Statement of Purpose. 3. Public License Fallback. Should any part of the Waiver for any reason be judged legally invalid or ineffective under applicable law, then the Waiver shall be preserved to the maximum extent permitted taking into account Affirmer's express Statement of Purpose. In addition, to the extent the Waiver is so judged Affirmer hereby grants to each affected person a royalty-free, non transferable, non sublicensable, non exclusive, irrevocable and unconditional license to exercise Affirmer's Copyright and Related Rights in the Work (i) in all territories worldwide, (ii) for the maximum duration provided by applicable law or treaty (including future time extensions), (iii) in any current or future medium and for any number of copies, and (iv) for any purpose whatsoever, including without limitation commercial, advertising or promotional purposes (the "License"). The License shall be deemed effective as of the date CC0 was applied by Affirmer to the Work. Should any part of the License for any reason be judged legally invalid or ineffective under applicable law, such partial invalidity or ineffectiveness shall not invalidate the remainder of the License, and in such case Affirmer hereby affirms that he or she will not (i) exercise any of his or her remaining Copyright and Related Rights in the Work or (ii) assert any associated claims and causes of action with respect to the Work, in either case contrary to Affirmer's express Statement of Purpose. 4. Limitations and Disclaimers. a. No trademark or patent rights held by Affirmer are waived, abandoned, surrendered, licensed or otherwise affected by this document. b. Affirmer offers the Work as-is and makes no representations or warranties of any kind concerning the Work, express, implied, statutory or otherwise, including without limitation warranties of title, merchantability, fitness for a particular purpose, non infringement, or the absence of latent or other defects, accuracy, or the present or absence of errors, whether or not discoverable, all to the greatest extent permissible under applicable law. c. Affirmer disclaims responsibility for clearing rights of other persons that may apply to the Work or any use thereof, including without limitation any person's Copyright and Related Rights in the Work. Further, Affirmer disclaims responsibility for obtaining any necessary consents, permissions or other rights required for any use of the Work. d. Affirmer understands and acknowledges that Creative Commons is not a party to this document and has no duty or obligation with respect to this CC0 or use of the Work. For more information, please see edit-0.1.5/README.md000064400000000000000000000012441046102023000120340ustar 00000000000000# `edit` [![crates.io](https://img.shields.io/crates/v/edit.svg)](https://crates.io/crates/edit) [![docs.rs](https://docs.rs/edit/badge.svg)](https://docs.rs/edit/) `edit` is a Rust library that lets you open and edit something in a text editor, regardless of platform. (Think `git commit`.) It works on Windows, Mac, and Linux, and knows about lots of different text editors to fall back upon in case standard environment variables such as `VISUAL` and `EDITOR` aren't set. let template = "Fill in the blank: Hello, _____!"; let edited = edit::edit(template)?; println!("after editing: '{}'", edited); // after editing: 'Fill in the blank: Hello, world!' edit-0.1.5/examples/edit-example.rs000064400000000000000000000005101046102023000153120ustar 00000000000000fn main() { let string = format!( "Hello world!\nYou are editing this file in '{}'.", edit::get_editor() .expect("can't find an editor") .to_str() .unwrap() ); let edited = edit::edit(string).expect("editing failed"); println!("after editing:\n{}", edited); } edit-0.1.5/src/lib.rs000064400000000000000000000313421046102023000124620ustar 00000000000000//! `edit` lets you open and edit something in a text editor, regardless of platform. //! (Think `git commit`.) //! //! It works on Windows, Mac, and Linux, and [knows about] lots of different text editors to fall //! back upon in case standard environment variables such as `VISUAL` and `EDITOR` aren't set. //! //! ```rust,ignore //! let template = "Fill in the blank: Hello, _____!"; //! let edited = edit::edit(template)?; //! println!("after editing: '{}'", edited); //! // after editing: 'Fill in the blank: Hello, world!' //! ``` //! //! [knows about]: ../src/edit/lib.rs.html#31-61 //! //! Features //! ======== //! //! The `edit` crate has the following optional features: //! //! - `better-path` *(enabled by default)* — Use //! [`which`](https://docs.rs/which) to locate executable programs in `PATH`. //! If this is disabled, programs are still looked up in `PATH`, but a basic //! search is used that does not check for executability. //! //! - `quoted-env` — Use [`shell-words`](https://docs.rs/shell-words) to split //! apart the values of the `VISUAL` and `EDITOR` environment variables. If //! this is disabled, the envvars are split up on whitespace. use std::{ env, ffi::OsStr, fs, io::{Error, ErrorKind, Result, Write}, path::{Path, PathBuf}, process::{Command, Stdio}, }; pub use tempfile::Builder; #[cfg(feature = "which")] use which::which; static ENV_VARS: &[&str] = &["VISUAL", "EDITOR"]; // TODO: should we hardcode full paths as well in case $PATH is borked? #[cfg(not(any(target_os = "windows", target_os = "macos")))] #[rustfmt::skip] static HARDCODED_NAMES: &[&str] = &[ // CLI editors "sensible-editor", "nano", "pico", "vim", "nvim", "vi", "emacs", // GUI editors "code", "atom", "subl", "gedit", "gvim", // Generic "file openers" "xdg-open", "gnome-open", "kde-open", ]; #[cfg(target_os = "macos")] #[rustfmt::skip] static HARDCODED_NAMES: &[&str] = &[ // CLI editors "nano", "pico", "vim", "nvim", "vi", "emacs", // open has a special flag to open in the default text editor // (this really should come before the CLI editors, but in order // not to break compatibility, we still prefer CLI over GUI) "open -Wt", // GUI editors "code -w", "atom -w", "subl -w", "gvim", "mate", // Generic "file openers" "open -a TextEdit", "open -a TextMate", // TODO: "open -f" reads input from standard input and opens with // TextEdit. if this flag were used we could skip the tempfile "open", ]; #[cfg(target_os = "windows")] #[rustfmt::skip] static HARDCODED_NAMES: &[&str] = &[ // GUI editors "code.cmd -n -w", "atom.exe -w", "subl.exe -w", // notepad++ does not block for input // Installed by default "notepad.exe", // Generic "file openers" "cmd.exe /C start", ]; #[cfg(feature = "better-path")] fn get_full_editor_path>(binary_name: T) -> which::Result { which(binary_name) } #[cfg(not(feature = "better-path"))] fn get_full_editor_path + AsRef>(binary_name: T) -> Result { if let Some(paths) = env::var_os("PATH") { for dir in env::split_paths(&paths) { if dir.join(&binary_name).is_file() { return Ok(dir.join(&binary_name)); } } } Err(Error::from(ErrorKind::NotFound)) } #[cfg(not(feature = "quoted-env"))] fn string_to_cmd(s: String) -> (PathBuf, Vec) { let mut args = s.split_ascii_whitespace(); ( args.next().unwrap().into(), args.map(String::from).collect(), ) } #[cfg(feature = "quoted-env")] fn string_to_cmd(s: String) -> (PathBuf, Vec) { match shell_words::split(&s) { Ok(mut v) if !v.is_empty() => (v.remove(0).into(), v), _ => { let mut args = s.split_ascii_whitespace(); ( args.next().unwrap().into(), args.map(String::from).collect(), ) } } } fn get_full_editor_cmd(s: String) -> Result<(PathBuf, Vec)> { let (path, args) = string_to_cmd(s); match get_full_editor_path(&path) { Ok(result) => Ok((result, args)), Err(_) if path.exists() => Ok((path, args)), Err(_) => Err(Error::from(ErrorKind::NotFound)) } } fn get_editor_args() -> Result<(PathBuf, Vec)> { ENV_VARS .iter() .filter_map(env::var_os) .filter(|v| !v.is_empty()) .filter_map(|v| v.into_string().ok()) .filter_map(|s| get_full_editor_cmd(s).ok()) .next() .or_else(|| { HARDCODED_NAMES .iter() .map(|s| s.to_string()) .filter_map(|s| get_full_editor_cmd(s).ok()) .next() }) .ok_or_else(|| Error::from(ErrorKind::NotFound)) } /// Find the system default editor, if there is one. /// /// This function checks several sources to find an editor binary (in order of precedence): /// /// - the `VISUAL` environment variable /// - the `EDITOR` environment variable /// - hardcoded lists of common CLI editors on MacOS/Unix /// - hardcoded lists of GUI editors on Windows/MacOS/Unix /// - platform-specific generic "file openers" (e.g. `xdg-open` on Linux and `open` on MacOS) /// /// Also, it doesn't blindly return whatever is in an environment variable. If a specified editor /// can't be found or isn't marked as executable (the executable bit is checked when the default /// feature `better-path` is enabled), this function will fall back to the next one that is. /// /// # Returns /// /// If successful, returns the name of the system default editor. /// Note that in most cases the full path of the editor isn't returned; what is guaranteed is the /// return value being suitable as the program name for e.g. [`Command::new`]. /// /// On some platforms, a text editor is installed by default, so the chances of a failure are low /// save for `PATH` being unset or something weird like that. However, it is possible for one not /// to be located, and in that case `get_editor` will return [`ErrorKind::NotFound`]. /// /// # Example /// /// ```rust,ignore /// use edit::get_editor; /// /// // will print e.g. "default editor: nano" /// println!("default editor:", get_editor().expect("can't find an editor").to_str()); /// ``` /// /// [`Command::new`]: https://doc.rust-lang.org/std/process/struct.Command.html#method.new /// [`ErrorKind::NotFound`]: https://doc.rust-lang.org/std/io/enum.ErrorKind.html#variant.NotFound pub fn get_editor() -> Result { get_editor_args().map(|(x, _)| x) } /// Open the contents of a string or buffer in the [default editor]. /// /// This function saves its input to a temporary file and then opens the default editor to it. /// It waits for the editor to return, re-reads the (possibly changed/edited) temporary file, and /// then deletes it. /// /// # Arguments /// /// `text` is written to the temporary file before invoking the editor. (The editor opens with /// the contents of `text` already in the file). /// /// # Returns /// /// If successful, returns the edited string. /// If the edited version of the file can't be decoded as UTF-8, returns [`ErrorKind::InvalidData`]. /// If no text editor could be found, returns [`ErrorKind::NotFound`]. /// Any errors related to spawning the editor process will also be passed through. /// /// [default editor]: fn.get_editor.html /// [`ErrorKind::InvalidData`]: https://doc.rust-lang.org/std/io/enum.ErrorKind.html#variant.InvalidData /// [`ErrorKind::NotFound`]: https://doc.rust-lang.org/std/io/enum.ErrorKind.html#variant.NotFound pub fn edit>(text: S) -> Result { let builder = Builder::new(); edit_with_builder(text, &builder) } /// Open the contents of a string or buffer in the [default editor] using a temporary file with a /// custom path or filename. /// /// This function saves its input to a temporary file created using `builder`, then opens the /// default editor to it. It waits for the editor to return, re-reads the (possibly changed/edited) /// temporary file, and then deletes it. /// /// Other than the custom [`Builder`], this function is identical to [`edit`]. /// /// # Arguments /// /// `builder` is used to create a temporary file, potentially with a custom name, path, or prefix. /// /// `text` is written to the temporary file before invoking the editor. (The editor opens with /// the contents of `text` already in the file). /// /// # Returns /// /// If successful, returns the edited string. /// If the temporary file can't be created with the provided builder, may return any error returned /// by [`OpenOptions::open`]. /// If the edited version of the file can't be decoded as UTF-8, returns [`ErrorKind::InvalidData`]. /// If no text editor could be found, returns [`ErrorKind::NotFound`]. /// Any errors related to spawning the editor process will also be passed through. /// /// [default editor]: fn.get_editor.html /// [`edit`]: fn.edit.html /// [`Builder`]: struct.Builder.html /// [`OpenOptions::open`]: https://doc.rust-lang.org/std/fs/struct.OpenOptions.html#errors /// [`ErrorKind::InvalidData`]: https://doc.rust-lang.org/std/io/enum.ErrorKind.html#variant.InvalidData /// [`ErrorKind::NotFound`]: https://doc.rust-lang.org/std/io/enum.ErrorKind.html#variant.NotFound pub fn edit_with_builder>(text: S, builder: &Builder) -> Result { String::from_utf8(edit_bytes_with_builder(text, builder)?) .map_err(|_| Error::from(ErrorKind::InvalidData)) } /// Open the contents of a string or buffer in the [default editor] and return them as raw bytes. /// /// See [`edit`], the version of this function that takes and returns [`String`]. /// /// # Arguments /// /// `buf` is written to the temporary file before invoking the editor. /// /// # Returns /// /// If successful, returns the contents of the temporary file in raw (`Vec`) form. /// /// [default editor]: fn.get_editor.html /// [`edit`]: fn.edit.html /// [`String`]: https://doc.rust-lang.org/std/string/struct.String.html pub fn edit_bytes>(buf: B) -> Result> { let builder = Builder::new(); edit_bytes_with_builder(buf, &builder) } /// Open the contents of a string or buffer in the [default editor] using a temporary file with a /// custom path or filename and return them as raw bytes. /// /// See [`edit_with_builder`], the version of this function that takes and returns [`String`]. /// /// Other than the custom [`Builder`], this function is identical to [`edit_bytes`]. /// /// # Arguments /// /// `builder` is used to create a temporary file, potentially with a custom name, path, or prefix. /// /// `buf` is written to the temporary file before invoking the editor. /// /// # Returns /// /// If successful, returns the contents of the temporary file in raw (`Vec`) form. /// /// [default editor]: fn.get_editor.html /// [`edit_with_builder`]: fn.edit_with_builder.html /// [`String`]: https://doc.rust-lang.org/std/string/struct.String.html /// [`Builder`]: struct.Builder.html /// [`edit_bytes`]: fn.edit_bytes.html pub fn edit_bytes_with_builder>(buf: B, builder: &Builder) -> Result> { let mut file = builder.tempfile()?; file.write_all(buf.as_ref())?; let path = file.into_temp_path(); edit_file(&path)?; let edited = fs::read(&path)?; path.close()?; Ok(edited) } /// Open an existing file (or create a new one, depending on the editor's behavior) in the /// [default editor] and wait for the editor to exit. /// /// # Arguments /// /// A [`Path`] to a file, new or existing, to open in the default editor. /// /// # Returns /// /// A Result is returned in case of errors finding or spawning the editor, but the contents of the /// file are not read and returned as in [`edit`] and [`edit_bytes`]. /// /// [default editor]: fn.get_editor.html /// [`Path`]: https://doc.rust-lang.org/std/path/struct.Path.html /// [`edit`]: fn.edit.html /// [`edit_bytes`]: fn.edit_bytes.html pub fn edit_file>(file: P) -> Result<()> { let (editor, args) = get_editor_args()?; let status = Command::new(&editor) .args(&args) .arg(file.as_ref()) .stdin(Stdio::inherit()) .stdout(Stdio::inherit()) .stderr(Stdio::inherit()) .output()? .status; if status.success() { Ok(()) } else { let full_command = if args.is_empty() { format!( "{} {}", editor.to_string_lossy(), file.as_ref().to_string_lossy() ) } else { format!( "{} {} {}", editor.to_string_lossy(), args.join(" "), file.as_ref().to_string_lossy() ) }; Err(Error::new( ErrorKind::Other, format!("editor '{}' exited with error: {}", full_command, status), )) } }