olets / zsh-abbr

The zsh manager for auto-expanding abbreviations, inspired by fish. ~13,000 unique cloners as of May '24, 580+ Homebrew installs 6/23-6/24
https://zsh-abbr.olets.dev
Other
517 stars 18 forks source link

Abbreviations not expanded after (( or $( #9

Open olets opened 4 years ago

olets commented 4 years ago
abbr -g a="abc"
a[Space] # expands
b a[Space] # expands
[[ a[Space] # expands
(( a[Space] # does not expand 😞
$( a[Space] # does not expand 😞

This is due to how zsh parses strings containing ((.

% mytest() {
  local words=(${(z)1})
  local count=${#words}
  local word_count=${(w)#words}
  echo $count
  echo $word_count
  echo $words[-1]
  echo ${(w)words: -1}
}

% mytest "a"
1
1
a
a

% mytest "a b"
2
2
b
b

% mytest "[[ a"
2
2
a
a

% mytest "(( a"
1
2
(( a
(( a

wontfix because I'm okay living with this, help wanted because ideas are welcome. I do want to rely on zsh's shell grammar parsing and word splitting (retreating to pre-a3c00f5 is not a solution).

farzadmf commented 2 years ago

Hi @olets , sad to see this πŸ™. I was about to create an issue for this. Is there any hack/workaround?

olets commented 2 years ago

What's your use case?

farzadmf commented 2 years ago

Basically, doing something like this:

my_var=$( echo <alias-i-want-to-expand> .... )
olets commented 2 years ago

What is the ...., what is the expansion, and what are you doing with my_var? A full real example will help me in making a recommendation.

farzadmf commented 2 years ago

Ah OK, sorry, I didn't think those are relevant πŸ˜›

More concrete example: I have set up something like abbr -g prof='profile=my_profile' for aws-cli, and I want to do something like this:

queues=$( aws <i-want-to-exapnd-'prof'-here> sqs list-queues )

Or, basically expand it "anywhere":

queues=$( aws sqs list-queues <i-want-to-exapnd-'prof'-here> )

My personal solution was to use ZSH global aliases (alias -g ...), and they seem to do what I had in mind.

olets commented 2 years ago

Ok cool some ideas…

Doesn't look like you really need the prof abbreviation, at least not in this context. How about an abbreviation one order higher?

% abbr -g q='$(aws sqs list-queues profile=my_profile)'
% foo q # q expands

(Can always keep the prof abbreviation too, if you need it elsewhere.)

You don't say what context you're using queues in, so maybe there's a vanilla way to get around the need for $() evaluation

% abbr -g q='aws sqs list-queues profile=my_profile'
% q | foo # q expands

You could even bind abbr-expand to a key (see Advanced in the README) and then abbr -g q='aws sqs list-queues profile=' and then q[your expand key]my_profile | foo but that's overly fancy for most scenarios.

There are a few plugins that add "suggestions from command history" and "search command history by any word in the command". Those will be helpful here. (I currently use zsh-history-substring-search and zsh-autosuggestions.) With that set up you might even find that you don't need an abbreviation or alias!

% foo $(aws sqs list-queues profile=my_profile) bar
% foo # zsh-autosuggestions or another history suggestion plugin will suggest 'foo $(aws sqs list-queries profile=my_profile) bar'
% bar
% foo # zsh-history-substring-search's history-substring-search-up key, or some other plugin, will take you to 'foo $(aws sqs list-queries profile=my_profile) bar' 
% bar # zsh-history-substring-search's history-substring-search-up key, or some other plugin, will fairly quickly take you to 'foo $(aws sqs list-queries profile=my_profile) bar' 
% sqs # zsh-history-substring-search's history-substring-search-up key, or some other plugin, will take you to 'foo $(aws sqs list-queries profile=my_profile) bar'

Another option is a function, especially if you need to run this AWS command with a variety of profiles.

# in zshrc
lq() {
  if (( $# )); then
    aws sqs list-queues profile=$1
    return
  fi

  aws sqs list-queues
}
% lq my_profile
% foo $(lq my_profile) bar

But my preference is to not use functions for small things like this, for the same reasons that I prefer abbreviations to aliases: I wouldn't want to forget the AWS command. Saving keystrokes is a high priority for me, but so is knowing the tools. I reserve functions for more complex things.

Hopefully there's a solution somewhere in those ideas!

--

edit: Depending on your reason for wanting an abbreviation for just the profile parameter, you might consider doing something with a new environment variable

# in zshrc
AWS_PROFILE=my_profile
% abbr -g q='aws sqs list-queues profile=$AWS_PROFILE'
% q[Enter]
% AWS_PROFILE=other_profile q[Enter] # q expands
# and even
% abbr o="AWS_PROFILE=other_profile"
% o q[Enter] # o and q expand

I personally prefer static abbreviations, but I know some people do dynamic abbreviations like that.

farzadmf commented 2 years ago

Wow, thank you @olets , that's so much to take in, I need to go through each and see which one is good for my use case


But, sadly, I mistyped the first command πŸ˜›

So, the proper way to pass profile to aws commnd is --profile=my_profile (the -- is needed)

I also have a Makefile that I've "designed" in a way to allow doing something like make list-queues profile=my_profile

So, in an ideal world, I would have a single abbreviation to expand profile=my_profile, and then:

One thing that could be a blocker with your solution(s) (I quickly went through them, so maybe I'm mistaken) is that, as you probably, know, there are a million permutations for running different aws commands, and if I'm to create an alias for each one, it could be very tedious

This "golden" abbreviation that I'm looking for is to modify a command with as few keystrokes as possible πŸ™‚