Skip to content

Conversation

@SandWoodJones
Copy link

Description

Fixes #11184

TODOs:

  • Changes to fish usage are reflected in user documentation/manpages.
  • Tests have been added for regressions fixed
  • User-visible changes noted in CHANGELOG.rst

if !self.matches_position(position) {
return false;
}
if !self.commands.is_empty() && !self.commands.contains(&command.to_owned()) {
Copy link
Contributor

Choose a reason for hiding this comment

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

would have been nice to add a test case to the commit message,
or (even better) to tests/checks/abbr.fish,
so reviewers don't have to read through the issue.

src/abbrs.rs Outdated
return false;
if self.commands.is_empty() {
if !command.is_empty() {
return false;
Copy link
Contributor

Choose a reason for hiding this comment

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

I don't really know this code but this feels like a bit hard to follow,
can we make it easier?

I think what the existing code is trying to do is,
return false if all of

  1. the abbr has any -c argument
  2. the actual command does not match any of the -c arguments

and you return false if all of

  1. there is no -c argument
  2. there is no command detected.

I don't understand why,
do you have a test case.

src/abbrs.rs Outdated
return false;
}
} else {
if command.is_empty() || !self.commands.contains(&command.to_owned()) {
Copy link
Contributor

Choose a reason for hiding this comment

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

I'm also not sure why we also special-case "command.is_empty()" in the other branch,
because why would self.commands ever contain an empty command?
If it doesn't that's probably a case of GIGO

src/abbrs.rs Outdated
.abbrs
.iter()
.any(|a| a.name == new_name && a.commands == commands),
"Target abbreviation name and commands already exist."
Copy link
Contributor

Choose a reason for hiding this comment

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

this assertion is no longer needed, because we already do

.expect("Abbreviation to rename was not found.")

below, which has the same meaning

src/abbrs.rs Outdated
.iter()
.position(|a| a.name == name && a.commands == commands);

if let Some(idx) = index {
Copy link
Contributor

Choose a reason for hiding this comment

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

use let-else here to reduce indentation

let Some(idx) = self.abbrs.position(...) else {
	return false;
};

src/abbrs.rs Outdated
if !self.abbrs.iter().any(|a| a.name == name) {
assert!(
self.used_names.remove(name),
"Name was not in used_names but should have been"
Copy link
Contributor

Choose a reason for hiding this comment

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

this code ("remove from used_names if necessary") is duplicated across both rename() erase(),
can we extract a simple function like fn on_remove(name: &wstr) to do it?

if abbrs
.list()
.iter()
.any(|a| a.name == *new_name && a.commands == opts.commands)
Copy link
Contributor

Choose a reason for hiding this comment

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

this should probably be stricter.
Consider

abbr f --command=foo ...
abbr fb --command=foo --command=bar ...
abbr --rename f --command=foo fb

It's probably not a good idea for this to be allowed, because they do conflict.

Copy link
Author

Choose a reason for hiding this comment

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

Thanks for the review. I'm not sure if I agree here as the resulting (name = "fb", commands = ["foo"]) doesn't conflict with (name = "fb", commands = ["foo", "bar"]). With the new logic we consider an abbr unique by their (name, commands) pair, instead of just their name.

Copy link
Contributor

Choose a reason for hiding this comment

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

it doesn't conflict in the data structure but it does when trying to use it. Hmm.

{
streams.err.append(wgettext_fmt!(
"%s %s: Abbreviation %s already exists, cannot rename %s\n",
"%s %s: Abbreviation %s with the specified command restrictions already exists, cannot rename %s\n",
Copy link
Contributor

Choose a reason for hiding this comment

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

probably better not to change the output if there are no command restrictions?
And if there are, we can mention the concrete ones:

Abbreviation dst already exists for commands 'foo', 'bar' and 'baz', cannot rename src

}
abbrs.rename(old_name, new_name);

abbrs.rename(old_name, new_name, &opts.commands);
Copy link
Contributor

Choose a reason for hiding this comment

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

The synopsis in doc_src/cmds/abbr.rst is

abbrs --rename OLD_WORD NEW_WORD

so it doesn't mention "--command" at all.

So we should either document this behavior,
or have "abbr --rename" error if OLD_WORD is ambiguous.

Either is fine by me.

if ret == EnvStackSetResult::Ok {
result = Ok(SUCCESS)
};
if opts.commands.is_empty() {
Copy link
Contributor

Choose a reason for hiding this comment

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

Wait, do abbreviations with commands have no _fish_abbr_ materialization?
I guess that might be true because that's a legacy thing.

But this change feels like an independent fix,
if that's true, it should go into a separate commit if possible.

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.

abbr --add --command conflicts with abbr

2 participants