Skip to content

fix(history): emit diagnostic when HISTFILE is unset for -a/-w#1146

Open
dashitongzhi wants to merge 5 commits into
reubeno:mainfrom
dashitongzhi:fix/history-histfile-diagnostic
Open

fix(history): emit diagnostic when HISTFILE is unset for -a/-w#1146
dashitongzhi wants to merge 5 commits into
reubeno:mainfrom
dashitongzhi:fix/history-histfile-diagnostic

Conversation

@dashitongzhi

Copy link
Copy Markdown

Summary

When HISTFILE is unset and no explicit file argument is provided, history -a and history -w previously silently succeeded with exit 0. Bash emits a diagnostic to stderr in the same situation.

This PR fixes the issue by emitting:

brush: history: HISTFILE: parameter null or not set

to stderr when the history file path resolves to None, matching bash's exact wording for compat-script friendliness.

Changes

  • brush-builtins/src/history.rs: Converted if let Some to match for both -a (append_session_to_file) and -w (write_session_to_file) code paths, adding a None arm that writes the diagnostic to stderr.

Notes

  • -n and -r already return "not yet implemented" errors, so they don't need the HISTFILE check yet.
  • The fix preserves the existing exit code (0) to match bash behavior.

Fixes #1135

Copilot AI review requested due to automatic review settings May 6, 2026 14:44

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR aligns history -a and history -w behavior with bash by emitting a stderr diagnostic when no effective history file can be determined (i.e., HISTFILE unset and no explicit file argument), while preserving the bash-compatible success exit code.

Changes:

  • Updated history -a and history -w code paths to handle None from get_effective_history_file_path by printing HISTFILE: parameter null or not set to stderr.
  • Refactored the previous if let Some(...) flow into match to make the None handling explicit.

Comment on lines +132 to +134
None => {
writeln!(stderr, "brush: history: HISTFILE: parameter null or not set")?;
}
Comment on lines +120 to +134
match get_effective_history_file_path(
config.default_history_file_path,
append_option.as_ref(),
) {
history.flush(
file_path,
true, /* append? */
true, /* unsaved items only */
config.time_format.is_some(), /* write timestamps? */
)?;
Some(file_path) => {
history.flush(
file_path,
true, /* append? */
true, /* unsaved items only */
config.time_format.is_some(), /* write timestamps? */
)?;
}
None => {
writeln!(stderr, "brush: history: HISTFILE: parameter null or not set")?;
}
Comment on lines 119 to 137
if let Some(append_option) = &self.append_session_to_file {
if let Some(file_path) = get_effective_history_file_path(
match get_effective_history_file_path(
config.default_history_file_path,
append_option.as_ref(),
) {
history.flush(
file_path,
true, /* append? */
true, /* unsaved items only */
config.time_format.is_some(), /* write timestamps? */
)?;
Some(file_path) => {
history.flush(
file_path,
true, /* append? */
true, /* unsaved items only */
config.time_format.is_some(), /* write timestamps? */
)?;
}
None => {
writeln!(stderr, "brush: history: HISTFILE: parameter null or not set")?;
}
}

return Ok(ExecutionResult::success());
Comment thread brush-builtins/src/history.rs Outdated
)?;
}
None => {
writeln!(stderr, "brush: history: HISTFILE: parameter null or not set")?;
Comment on lines +149 to +163
match get_effective_history_file_path(
config.default_history_file_path,
write_option.as_ref(),
) {
history.flush(
file_path,
false, /* append? */
false, /* unsaved items only? */
config.time_format.is_some(), /* write timestamps? */
)?;
Some(file_path) => {
history.flush(
file_path,
false, /* append? */
false, /* unsaved items only? */
config.time_format.is_some(), /* write timestamps? */
)?;
}
None => {
writeln!(stderr, "brush: history: HISTFILE: parameter null or not set")?;
}
@reubeno

reubeno commented May 7, 2026

Copy link
Copy Markdown
Owner

@dashitongzhi Thanks for the contribution!

The change looks relatively straightforward. I've unblocked the PR checks to run and will take another look.

@github-actions

github-actions Bot commented May 7, 2026

Copy link
Copy Markdown

Performance Benchmark Report

Benchmark name Baseline (μs) Test/PR (μs) Delta (μs) Delta %
clone_shell_object 17.40 μs 17.80 μs 0.40 μs ⚪ Unchanged
eval_arithmetic 0.15 μs 0.15 μs 0.00 μs ⚪ Unchanged
expand_one_string 1.51 μs 1.62 μs 0.11 μs 🟠 +7.33%
for_loop 30.68 μs 30.88 μs 0.20 μs ⚪ Unchanged
full_peg_complex 57.93 μs 57.22 μs -0.72 μs ⚪ Unchanged
full_peg_for_loop 6.45 μs 6.21 μs -0.24 μs 🟢 -3.69%
full_peg_nested_expansions 16.66 μs 16.49 μs -0.18 μs 🟢 -1.07%
full_peg_pipeline 4.29 μs 4.28 μs -0.00 μs ⚪ Unchanged
full_peg_simple 1.83 μs 1.83 μs -0.00 μs ⚪ Unchanged
function_call 3.35 μs 3.50 μs 0.15 μs ⚪ Unchanged
instantiate_shell 55.17 μs 55.87 μs 0.70 μs ⚪ Unchanged
instantiate_shell_with_init_scripts 27442.64 μs 27548.16 μs 105.52 μs ⚪ Unchanged
parse_peg_bash_completion 2108.89 μs 2113.07 μs 4.18 μs ⚪ Unchanged
parse_peg_complex 19.86 μs 18.59 μs -1.27 μs 🟢 -6.38%
parse_peg_for_loop 1.91 μs 1.89 μs -0.02 μs ⚪ Unchanged
parse_peg_pipeline 1.96 μs 2.12 μs 0.15 μs 🟠 +7.74%
parse_peg_simple 1.06 μs 1.12 μs 0.06 μs 🟠 +5.95%
run_echo_builtin_command 16.87 μs 16.89 μs 0.02 μs ⚪ Unchanged
tokenize_sample_script 3.57 μs 3.55 μs -0.02 μs ⚪ Unchanged

Code Coverage Report: Only Changed Files listed

Package Base Coverage New Coverage Difference
brush-builtins/src/history.rs 🟢 89.06% 🟢 89.23% 🟢 0.17%
brush-core/src/jobs.rs 🔴 49.55% 🟠 50.91% 🟢 1.36%
Overall Coverage 🟢 75.19% 🟢 75.21% 🟢 0.02%

Minimum allowed coverage is 70%, this run produced 75.21%

Test Summary: bash-completion test suite

Outcome Count Percentage
✅ Pass 1582 75.01
❗️ Error 18 0.85
❌ Fail 155 7.35
⏩ Skip 339 16.07
❎ Expected Fail 13 0.62
✔️ Unexpected Pass 2 0.09
📊 Total 2109 100.00

@reubeno reubeno left a comment

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the contribution, and for your patience. I left one comment that I'd like you to address; other than that it's looking good.

Comment thread brush-builtins/src/history.rs Outdated
None => {
writeln!(
stderr,
"brush: history: HISTFILE: parameter null or not set"

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As copilot's auto-comments called out, brush-core is embeddable in differently name shell apps, so we shouldn't hard-code brush.

If you look elsewhere in the code base you can see examples of what other builtins do. (Most of them probably omit the shell name, although the shell name can be dynamically queried via .current_shell_name() on the shell object.)

Could you please update this and the other error below accordingly?

dashitongzhi and others added 4 commits June 25, 2026 11:53
When  is unset and no explicit file argument is provided,
 and  previously silently succeeded with exit 0.
Bash emits a diagnostic in this situation.

This change converts the  pattern to  for both
 (append_session_to_file) and  (write_session_to_file) code
paths, emitting the following diagnostic to stderr when the history
file path resolves to None:

    brush: history: HISTFILE: parameter null or not set

This matches bash's exact wording for compat-script friendliness.

Fixes reubeno#1135
@dashitongzhi dashitongzhi force-pushed the fix/history-histfile-diagnostic branch from 8a5e0d7 to 90c747b Compare June 25, 2026 03:56
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

bug: history -a/-w/-n/-r silently no-op on unset HISTFILE; bash emits diagnostic

3 participants