fish

Fish Abbreviation to Run Heredocs in Bash


I am trying to write an abbreviation that will do the following:

if there is << in the whole buffer somewhere, it will enclose it with bash -c "<the-buffer>"

So, If I run

tee $HOME/Desktop/test << END
I am testing!
END

it will run the following instead.

bash -c "tee $HOME/Desktop/test << END
I am testing!
END"

The code I came up with is:

function run_in_bash
    # Run the command in bash
    bash -c "(commandline --current-buffer)"
end

abbr --add run_in_bash_abbr --regex '.*<<.*' --function run_in_bash

But now when I am running:

tee $HOME/Desktop/test << END
I am testing!
END

It says fish: Expected a string, but found a redirection. What can i do here?


Solution

  • There are a few misunderstandings here, and unfortunately one of them means this approach is fundamentally unworkable.

    The first is that the abbr function needs to print the replacement text, not run it.

    So you would do echo bash -c \'"$(commandline --current-buffer)"\', not directly bash -c "...". It also has to be $() so the substitution happens there and it prints it with the commandline inserted. You would also have to escape the buffer text so it is used as a single argument - commandline --current-buffer | string escape.

    The second, and this is what makes this approach unworkable, is that the abbreviation is triggered by the last token, and the regex is only matched against that one token.

    That means once you enter << , the abbreviation runs, and replaces << and only << with whatever it prints.

    (or at least it would, but since << isn't a valid token in fish it runs the abbreviation on the < separately, so you cannot actually match << with an abbreviation)