We sometimes use explicit reclaim() and sometimes rely on the drop
implementation. This adds an unnecesary step to reading all uses of
this code. Make this consistent. Use drop everywhere though we could
use explicit reclaim too.
Prior to f417cbc981 (Show soft-wrapped portions in autosuggestions,
2025-12-11), we'd truncate autosuggestions before the right prompt.
We no longer do that for autosuggestions that soft-wrap, which means
we try to draw both right prompt and suggestion in the same space.
Make suggestion paint over right prompt for now, since this seems to
be a simple and robust solution. We can revisit this later.
Fixes#12255
If "will_replace_token" is set, we generally only consider
appending completions. This changed in commit 656b39a0b3 (Also show
case-insensitive prefix matches in completion pager, 2025-11-23) which
also allowed icase completions as long as they are also prefix matches.
Such replacing completions might cause the common prefix to be empty,
which breaks the appending completions.
Fix this by not considering these replacing completions for the
common-prefix computation. The pager already doesn't show the prefix
for these completions specifically.
Fixes#12249
We skip completions where "will_replace_token != c.replaces_token()".
This means that
- if will_replace_token, we filter out non-replacing completions.
But those do not exist because, by definition, will_replace_token
is true iff there are no non-replacing completions.
- if !will_replace_token, we filter out replacing completions.
From the definition of will_replace_token follows that there is
some non-replacing completion, which must be a prefix or exact match.
Since we've filtered by rank, any replacing ones must have the same rank.
So the replacement bit must be due to smartcase. Smartcase
completions are already passed through explicitly here since
656b39a0b3 (Also show case-insensitive prefix matches in completion
pager, 2025-11-23).
So the cases where we 'continue' here can never happen.
Remove this redundant check.
The tuple (will_replace_token, all_matches_exact_or_prefix) can never
be (false, false).
Proof by contraction:
1. Goal: show unsatisfiability of: !will_replace_token && !all_matches_exact_or_prefix
2. Substitute defintions: !all(replaces) && !all(is_exact_or_prefix)
3. wlog, !replaces(c1) && !is_exact_or_prefix(c2)
4. since c1 and c2 have same rank we know that !is_exact_or_prefix(c1)
5. !is_exact_or_prefix() implies requires_full_replacement()
6. all callers that create a Completion from StringFuzzyMatch::try_create(),
set CompleteFlags::REPLACE_TOKEN if requires_full_replacement(),
so requires_full_replacement() implies replaces()
7. From 4-6 follows: !is_exact_or_prefix(c1) implies replaces(c1), which is a contradiction
A recent change attempted this:
let result: std::io::Result<()> = { code()? }
However this doesn't initialize the Result on error - instead it
returns from the function, meaning that the error would be silently
dropped.
Fix that by reporting the error at the call site instead.
Commit fbad0ab50a (reset_abandoning_line: remove redundant
allocations, 2025-11-13) uses byte count of ⏎ (3) instead of char
count (1), thus overestimating the number of spaces this symbol takes.
Fixes#12246
Rust has this annoying design where all of the syscall conveniences on
File assume that it owns its fd; in particular this means that we can't
easily construct File from stdin, a raw file descriptor, etc.
The usual workarounds are to construct a File and then mem::forget it
(this is apparently idiomatic Rust!). But this has problems of its own:
for example it can't easily be used in Drop.
Introduce BorrowedFdFile which wraps File with ManuallyDrop and then
never drops the file (i.e. it's always forgotten). Replace some raw FDs
with BorrowedFdFile.
Prior to this commit, this code:
fish_indent <&-
would panic as we would construct a File with a negative fd.
Check for a closed fd as other builtins do.
Since fish_indent became a builtin, it cannot be canceled with control-C,
because Rust's `read_to_end` retries on EINTR. Add our own function which
propagates EINTR and use it.
Fixes#12238
Commit 7996637db5 (Make fish immediately show color changes again,
2025-12-01) repaints unnecessarily when a local unexported color
variable changes. Also, it repaints when the change comes from
fish_prompt, causing an easy infinite loop. Same when changing TERM,
COLORTERM and others.
This feature is relevant when using a color-theme aware theme, so
try to keep it. Repaint only on global/universal changes.
Also ignore changes if already repainting fish prompt.
This change may be at odds with concurrent execution (parser should
not care about whether we are repainting) but that's intentional
because of 1. time constraints and 2. I'm not sure what the solution
will look like; we could use the event infrastructure. But a lot of
existing variable listeners don't use that.
Extract a context object we pass whenever we mutate the environment; While
at it, use it to pass EnvMode::USER, to reduce EnvMode responsibilities.
Fixes#12233