Skip to content

Commit 0b8c1ae

Browse files
committed
Avoid manual tempfile implementation in get_text::from_editor()
Let's set an example in code that is supposed to be used in many comands, more akind to a CLI-STD.
1 parent 9e0f170 commit 0b8c1ae

File tree

6 files changed

+26
-23
lines changed

6 files changed

+26
-23
lines changed

Cargo.lock

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

crates/but/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -116,6 +116,7 @@ minus = { version = "5.6.1", default-features = false, features = [
116116
] }
117117
unicode-width = "0.2"
118118
cfg-if = "1.0.4"
119+
tempfile.workspace = true
119120

120121
[dev-dependencies]
121122
but-core = { workspace = true, features = ["testing"] }

crates/but/src/command/legacy/commit.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -497,7 +497,7 @@ fn get_commit_message_from_editor(
497497
template.push_str("#\n");
498498

499499
// Read the result from the editor and strip comments
500-
let message = tui::get_text::from_editor_no_comments("but_commit_msg", &template)?;
500+
let message = tui::get_text::from_editor_no_comments("commit_msg", &template)?;
501501
Ok(message)
502502
}
503503

crates/but/src/command/legacy/describe.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -236,7 +236,7 @@ fn get_commit_message_from_editor(
236236
template.push_str("#\n");
237237

238238
// Read the result and strip comments
239-
let message = tui::get_text::from_editor_no_comments("but_commit_msg", &template)?;
239+
let message = tui::get_text::from_editor_no_comments("commit_msg", &template)?;
240240

241241
if message.is_empty() {
242242
bail!("Aborting due to empty commit message");
@@ -255,7 +255,7 @@ fn get_branch_name_from_editor(current_name: &str) -> Result<String> {
255255
template.push_str("# with '#' will be ignored, and an empty name aborts the operation.\n");
256256
template.push_str("#\n");
257257

258-
let branch_name = tui::get_text::from_editor_no_comments("but_branch_name", &template)?;
258+
let branch_name = tui::get_text::from_editor_no_comments("branch_name", &template)?;
259259

260260
if branch_name.is_empty() {
261261
bail!("Aborting due to empty branch name");

crates/but/src/command/legacy/forge/review.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -564,7 +564,7 @@ fn get_review_body_from_editor(
564564
template.push_str("# with '#' will be ignored, and an empty body is allowed.\n");
565565
template.push_str("#\n");
566566

567-
let body = get_text::from_editor_no_comments("but_review_body", &template)?;
567+
let body = get_text::from_editor_no_comments("review_body", &template)?;
568568
Ok(body)
569569
}
570570

@@ -606,7 +606,7 @@ fn get_review_title_from_editor(
606606
template.push_str("# with '#' will be ignored, and an empty title aborts the operation.\n");
607607
template.push_str("#\n");
608608

609-
let title = get_text::from_editor_no_comments("but_review_title", &template)?;
609+
let title = get_text::from_editor_no_comments("review_title", &template)?;
610610

611611
if title.is_empty() {
612612
anyhow::bail!("Aborting due to empty review title");

crates/but/src/tui/get_text.rs

Lines changed: 19 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,13 @@ use anyhow::Result;
33
use bstr::ByteSlice;
44
use std::ffi::OsStr;
55

6-
/// Launches the user's preferred text editor to edit some initial text,
7-
/// identified by a unique identifier (to avoid temp file collisions).
8-
/// Returns the edited text, with comment lines (starting with '#') removed.
9-
pub fn from_editor_no_comments(identifier: &str, initial_text: &str) -> Result<String> {
10-
let content = from_editor(identifier, initial_text)?;
6+
/// Launches the user's preferred text editor to edit some `initial_text`,
7+
/// identified by a `filename_safe_intent` to help the user understand what's wanted of them.
8+
/// Note that this string must be valid in filenames.
9+
///
10+
/// Returns the edited text, with comment lines (starting with `#`) removed.
11+
pub fn from_editor_no_comments(filename_safe_intent: &str, initial_text: &str) -> Result<String> {
12+
let content = from_editor(filename_safe_intent, initial_text)?;
1113

1214
// Strip comment lines (starting with '#')
1315
let filtered_lines: Vec<&str> = content
@@ -18,22 +20,25 @@ pub fn from_editor_no_comments(identifier: &str, initial_text: &str) -> Result<S
1820
Ok(filtered_lines.join("\n").trim().to_string())
1921
}
2022

21-
/// Launches the user's preferred text editor to edit some initial text,
22-
/// identified by a unique identifier (to avoid temp file collisions).
23-
/// Returns the edited text.
23+
/// Launches the user's preferred text editor to edit some `initial_text`,
24+
/// identified by a `filename_safe_intent` to help the user understand what's wanted of them.
25+
/// Note that this string must be valid in filenames.
26+
///
27+
/// Returns the edited text verbatim.
2428
pub fn from_editor(identifier: &str, initial_text: &str) -> Result<String> {
2529
let editor_cmd = get_editor_command()?;
2630

2731
// Create a temporary file with the initial text
28-
let temp_dir = std::env::temp_dir();
29-
let temp_file = temp_dir.join(format!("{}_{}", identifier, std::process::id()));
30-
31-
std::fs::write(&temp_file, initial_text)?;
32+
let tempfile = tempfile::Builder::new()
33+
.prefix(&format!("but_{identifier}_"))
34+
.suffix(".txt")
35+
.tempfile()?;
36+
std::fs::write(&tempfile, initial_text)?;
3237

3338
// The editor command is allowed to be a shell expression, e.g. "code --wait" is somewhat common.
3439
// We need to execute within a shell to make sure we don't get "No such file or directory" errors.
3540
let status = gix::command::prepare(editor_cmd)
36-
.arg(&temp_file)
41+
.arg(tempfile.path())
3742
.stdin(std::process::Stdio::inherit())
3843
.stdout(std::process::Stdio::inherit())
3944
.with_shell()
@@ -43,11 +48,7 @@ pub fn from_editor(identifier: &str, initial_text: &str) -> Result<String> {
4348
if !status.success() {
4449
return Err(anyhow::anyhow!("Editor exited with non-zero status"));
4550
}
46-
47-
// Read the edited text back
48-
let edited_text = std::fs::read_to_string(&temp_file)?;
49-
std::fs::remove_file(&temp_file).ok(); // Best effort to clean up
50-
Ok(edited_text)
51+
Ok(std::fs::read_to_string(&tempfile)?)
5152
}
5253

5354
/// Get the user's preferred editor command.

0 commit comments

Comments
 (0)