Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

support history expansion (e.g., bash's !!, bang bang, and !$, bang dollar, tokens) #288

Closed
cometpeak opened this issue Aug 20, 2012 · 103 comments

Comments

@cometpeak
Copy link

It appears that the double-bang does not work and is somehow interpreted as a program which sudo unsuccessfully tries to locate. This occurs on Ubuntu 12.04 LTS with fish-shell compiled from source.

Steps to repro:

  1. Execute any command:

    $ ls

  2. Execute the previous command as root:

    $ sudo !!
    sudo: !!: command not found

Expected behavior:

Command sudo !! executes previously executed command (ls) as root.

I also checked that the issue isn't caused by sudo by following repro steps in bash, which behaved as expected.

Also, note that an earlier version of fish-shell on Mac OS X 10.7 did not have this problem and sudo !! worked as expected.

@siteshwar
Copy link
Contributor

siteshwar commented Aug 20, 2012

It is discussed in documentation FAQs : http://fishshell.com/docs/current/faq.html#faq-history

@cometpeak
Copy link
Author

Thanks for the clarification.

I understand the rationale for removing history characters. However, while I understand the rationale for this and that it is possible to use C-e and C-a instead of End and Home, for many users, especially those used to !! and those on a laptop that do not have Home and End keys, it is still much easier to type sudo !! than Up+C-a+sudo.

Would you still consider restoring functionality of history substitution tokens?

@maxfl
Copy link
Contributor

maxfl commented Dec 11, 2012

Since it's a rare case where !! is more comfortable to use, try the following function:

function sudo!!
    eval sudo $history[1]
end

which is called just by "sudo!!".

Or the other possibility which I use:

function .runsudo --description 'Run current command line as root'
    commandline -C 0
    commandline -i 'sudo '
    commandline -f execute
end
bind \es .runsudo

Then by pressing M-S I run the current command line with sudo put just in front of it.
Or by modifying this example you can make a function which will put the previous commandline in the current one and bind it for example to '\e!'. This approach is better then simple use of '!!' because it gives you the opportunity to see and update the commandline before the execution.

@pooriaazimi
Copy link

I made a slight variation of the last command:

  function .runsudo --description 'Run current command line as root'
    set cursor_pos (echo (commandline -C) + 5 | bc)
    commandline -C 0
    commandline -i 'sudo '
    commandline -C "$cursor_pos"
  end
  bind \es ".runsudo"

It saves the cursor position instead of outright executing it.

@tyilo
Copy link
Contributor

tyilo commented Aug 16, 2013

!$ would also be nice to have

@KamilaBorowska
Copy link
Contributor

function sudo
    if test "$argv" = !!
        eval command sudo $history[1]
    else
        command sudo $argv
    end
end

sudo !! for people who still use !! for some reason.

@cometpeak
Copy link
Author

Thanks. There is a very sizable chunk of people who use sudo !! give that this syntax is supported across many other shells including bash and zsh. sudo !! is easier to type than using the home and end keys since those keys are farther away.

I would suggest having the above function be included with fish-shell by default.

@ridiculousfish
Copy link
Member

!! is a good candidate for an abbreviation (#731)

@ddevault
Copy link

Expressing support for !! and related shortcuts. It doesn't hurt to add it and it feels like fish is just shoving personal philosophy at its users.

@ridiculousfish
Copy link
Member

My current thinking of the ideal solution is that !! ought to be an abbreviation (#731), and we implement function signatures (#478) to support subcommands (a command that takes a command, like sudo). Then abbreviations expand in subcommand positions, so that 'sudo !!' will expand.

@zanchey zanchey mentioned this issue Oct 30, 2013
@rahulsundaram
Copy link

Adding myself

@VioletHynes
Copy link

Despite it being old, it's a feature that really should come as default in Fish. There's no reason not to have it - if you don'r want to use it personally, that's fine, but having an extra command doesn't really hurt anyone - people like doing things different ways.

@ridiculousfish
Copy link
Member

The way !! is implemented in most shells does hurt people. For example, consider this command:

echo fish is great!!

in bash / zsh / tcsh, this will do something unexpected and horrible, because the !! is magic syntax. This is the sort of weird interactions that fish tries very hard to avoid.

My suggestion was to implement !! not as magic syntax, but as an alias. This means it would only do something special in 'command position' - it won't expand in arguments. It also keeps the feature set of fish down, which is desirable.

To make that useful, we would need to teach fish about subcommands, with sudo being the most common example, but also time, strace, etc. fish would then expand aliases in "subcommand position", which is a cool and useful feature in its own right.

@ddevault
Copy link

Your proposed solution falls apart when you consider sudo echo fish is great!!. The same argument can be made of all syntax: isn't echo I really like fish (the shell)! also confusing? I also worry that a list of "subcommands" would be impossible to maintain and would reduce flexibility.

@ridiculousfish
Copy link
Member

With aliases, only commands get expanded, and fish would know which arguments are (sub)commands and which are not. So sudo echo fish is great!! would not perform last-command-expansion, but instead pass a literal "great!!" to sudo (and thereby to echo). I claim that is what the user expected. See the discussion about abbreviations (#731) and function signatures (#478) for the design and rationale.

SirCmpwn is correct that requiring comprehensive function signatures is a disadvantage of the alias approach, and also that other syntactic elements are confusing. Real-life examples include the annoyance of brace expansion with git (#434) or wildcards (#967, among others). Syntax comes with a high cost, and we try to eliminate syntax when it's redundant with other features (e.g. #354).

Anyways that's my argument for why supporting !! as an elementary syntactic element is a no-go. However I'm open to introducing it in ways that don't require modifying fish syntax.

@ddevault
Copy link

I think the comparison with {} is a poor one. In fish, braces work differently than other shells. People only trip up on it when they expect it to work like bash and friends. The !! syntax should work the same as other common shells. Also, !! isn't something I'd expect to see in commands often enough to cause issue. In fact, I'd expect the number of times people have tried and failed to use !! with fish far outnumbers the number of times someone has used a literal !! in a command.

@KamilaBorowska
Copy link
Contributor

I claim that ! is confusing in other shells, and it would be better if it wasn't implemented this way. For example, at http://codegolf.stackexchange.com/a/17776/3103 I put simple "Hello, world!" program written in UNIX shell that fails because of ! (in Ridiculous Runtime Errors question). It even got seven upvotes, so I can imagine this feature can be surprising when you don't want to use it.

However, !! by itself should be fine, because how often user will write !! as a token? Then again, adding !! would encourage adding other history substitution patterns, some of which could be annoying.

@codeurge
Copy link

Adding myself - just ran into this my first weekend with fish. Should definitely be supported.

@LeonardDrs
Copy link

Adding myself - need this.

@mrak
Copy link
Contributor

mrak commented Jun 7, 2014

For those desiring this, the function and bindings mentioned earlier in the discussion have given me an easier workflow for prepending sudo or sudoing the last command than the typical sudo !! one.

You should give them a try. It made me go revisit my readline and zsh configs to have similar bindings.

It turns seven keystrokes (two of those shifted) into a single binding.

@VioletHynes
Copy link

Regardless of what you like - is there really any reason for !! not to be supported? Everyone has different things that work for them, and though some people might enjoy using the up arrow, a lot of people enjoy using !!, and honestly, why would it be a bad thing? Those who don't want it don't have to use it.

Surely it's not that hard to implement?...

Yes, I know you can hack it together with fish scripting, but it does not work in the same way as in bash or similar shells, which was quite convenient a lot of the time.

@ridiculousfish
Copy link
Member

See my comment above for my rationale for why I don't want to introduce this the way that bash and zsh do it (as a new syntactic element), and my proposal for a way it could be done that keeps with the fish philosophy.

@gillham
Copy link

gillham commented Mar 9, 2015

The argument of "echo fish is great!!" being better than using '!!' for history is a bit weak, but I understand the point. Seems like a simple "set shell_history advanced" or something could allow it for people willing to risk "echo fish is great!!" getting an error message.

Nevertheless, my use case of '!!' is similar but could be avoided with some feature enhancement perhaps.

For example on my mac with bash:
$ brew update
$ brew outdated
$ brew fetch !!

So I somewhat regularly use the output of the previous command for a new command.
With fish I can do this:
$ brew fetch (brew outdated)
Now at some point perhaps that will be a suggestion I can use, but what I really need is to be able to search the history within the () block.
e.g.:
$ brew fetch (bre)

Unfortunately even though fish is fairly proud of using () for sub-commands instead of "confusing" backticks and such, it doesn't really treat them as such until you hit enter. At least that is what I see.

If fish would allow a history search after the first '(' (aka a subcommand) I think it would be easier to handle not having ! history manipulation.

@ridiculousfish
Copy link
Member

If I understand the suggestion, it's that when you press up arrow, it should perform history replacement only within the innermost subcommand instead of the entire command line.

@ddevault
Copy link

ddevault commented Mar 9, 2015

👎

I still support simply implementing bash-style !!.

@mrak
Copy link
Contributor

mrak commented Mar 9, 2015

I'd prefer :up_arrow:, Ctrl+p and command history search working in subcommand positions over introducing !!

The entire history API of other shells is confusing enough that people usually only remember !! from it.

@gillham
Copy link

gillham commented Mar 9, 2015

Correct. That would be convenient and fairly easily replace the '!!' Or !keyword use.

@faho faho added the duplicate label Dec 11, 2019
@faho faho removed this from the fish-future milestone Dec 11, 2019
@scooter-dangle
Copy link

@tukusejssirs and @ClickSentinel, have you tried adding the code at #288 (comment) to your config?

I've had a variant of that for several years (modified from an issue (this issue, maybe?) in my config, and it's one of the pieces of shell ergonomics I rely the most on. (Also, especially with the additional case I have in my variant to do an upward token search using the string prior to the !$, it's one of the things I'm most annoyed to not have when working in bash.)

My variant (or maybe I stole the variation...can't remember 🤷‍♂️ ):

function bind_bang
    switch (commandline --current-token)[-1]
    case "!"
        # Without the `--`, the functionality can break when completing
        # flags used in the history (since, in certain edge cases
        # `commandline` will assume that *it* should try to interpret
        # the flag)
        commandline --current-token -- $history[1]
        commandline --function repaint
    case "*"
        commandline --insert !
    end
end

function bind_dollar
    switch (commandline --current-token)[-1]
    # This case lets us still type a literal `!$` if we need to (by
    # typing `!\$`). Probably overkill.
    case "*!\\"
        # Without the `--`, the functionality can break when completing
        # flags used in the history (since, in certain edge cases
        # `commandline` will assume that *it* should try to interpret
        # the flag)
        commandline --current-token -- (echo -ns (commandline --current-token)[-1] | head -c '-1')
        commandline --insert '$'
    case "!"
        commandline --current-token ""
        commandline --function history-token-search-backward


    # Main difference from referenced version is this `*!` case
    # =========================================================
    #
    # If the `!$` is preceded by any text, search backward for tokens
    # that contain that text as a substring. E.g., if we'd previously
    # run
    #
    #   git checkout -b a_feature_branch
    #   git checkout master
    #
    # then the `fea!$` in the following would be replaced with
    # `a_feature_branch`
    #
    #   git branch -d fea!$
    #
    # and our command line would look like
    #
    #   git branch -d a_feature_branch
    #
    case "*!"
        # Without the `--`, the functionality can break when completing
        # flags used in the history (since, in certain edge cases
        # `commandline` will assume that *it* should try to interpret
        # the flag)
        commandline --current-token -- (echo -ns (commandline --current-token)[-1] | head -c '-1')
        commandline --function history-token-search-backward
    case "*"
        commandline --insert '$'
    end
end

function fish_user_key_bindings
    bind ! bind_bang
    bind '$' bind_dollar
end

@nitantsoni
Copy link

Thanks @scooter-dangle this works even better than #228

@psychoslave
Copy link

There are cases where Fish will provide more idiomatic way to do some action:

LANG=C :
fish: Unsupported use of '='. To run ':' with a modified environment, please use 'env LANG=C :…'

Maybe !! could also, by default, generate such a message suggesting an alternative more idiomatic way to do it?

However the proposal should be just as efficient. Compare:

  • sudo !!<enter>, all from the base position of hands on the keyboard
  • <up><home>sudo <enter>, as suggested in Fish’s FAQ which seems requiring more or less moves of hands depending on where and are on the keyboard.
  • <C-p><Ca>sudo <enter>, accessible without moving hands , which also works with defaults of Bash, ZSH and maybe more, so users can adopt new habit which is a portable when they have to deal with other shells.

For !$, suggesting <alt-.> seems fine, doesn't it?

@fish-shell fish-shell locked as resolved and limited conversation to collaborators May 21, 2020
@fish-shell fish-shell unlocked this conversation Nov 2, 2021
@fish-shell fish-shell deleted a comment from faho Nov 2, 2021
@fish-shell fish-shell locked as resolved and limited conversation to collaborators Oct 19, 2022
@floam
Copy link
Member

floam commented Oct 30, 2022

I think it was a mistake to mark this as a duplicate and lock conversation: the mega-super-duper abbreviation plans don't obviate this issue. Abbreviations will be the mechanism used to implement history expansion but the way this was triaged suggests fish-shell developers specifically decided not to ship the feature or plan on the story being "users should implement it themselves". We can expect a separate PR implementing history expansion after the new abbr lands.

@floam floam added this to the fish-future milestone Oct 30, 2022
@floam floam reopened this Oct 30, 2022
@fish-shell fish-shell unlocked this conversation Oct 30, 2022
@nyarly
Copy link
Contributor

nyarly commented Oct 31, 2022

Is the proposal to add a default abbreviation for !!, @floam?

@floam
Copy link
Member

floam commented Oct 31, 2022

from the PR

Here is the much-longed-for history expansion (#288). I think we should ship this, but it would be a separate PR:

function last_history_item
    echo $history[1]
end
abbr -a !! --position anywhere --function last_history_item --quiet

After the enhanced abbr lands we'll consider shipping a default !! abbreviation.

@nyarly
Copy link
Contributor

nyarly commented Oct 31, 2022

Right on. When that lands, I look forward to configuring without --quiet which IIUC would be effectively the same as the bind hack I'm using now - replacing !! with history[1] in place. I've found this 100% better than the Bash behavior.

@wleoncio
Copy link

Shouldn't this issue be closed as resolved, since PR #9313 has been merged into master and fish 3.6.1 (containing the changes) has been released?

Thanks to bringing this feature into Fish, BTW! 🥳

@faho
Copy link
Member

faho commented Mar 27, 2023

Yeah I'm closing this in favor of #9462 - it's possible to add this now, so the question is if we want it by default.

This issue is massive, so it helps to have something a bit more focused.

@faho faho closed this as completed Mar 27, 2023
@faho faho modified the milestones: fish-future, fish 3.6.0 Mar 27, 2023
@github-actions github-actions bot locked as resolved and limited conversation to collaborators May 27, 2024
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

No branches or pull requests