Zsh function: forward completion to subfunction - autocomplete

Many times I end up writting wrapper function around existing ones, for instance:
function gl {
some_computed_stuff=...
git --no-pager log --reverse $some_computed_stuff "$#"
}
function m {
make "$#" && notify-send success || notify-send failed
}
I know that aliases keep autocompletion but sometimes functions are required and in that case autocompletion is lost.
For instance here I would like to keep git log completion for my function gl or make completion for m.
I tried to add compctl -K _git gl but no suggestions are made. It won't work anyway since I must somehow find how to provide log argument to _git autocompletion script as well, so my question is:
Is there a way to make ZSH (but also bash) understand that typing gl is the exact equivalent of git log? Something like (for ZSH only):
compctl 'git log' gl
compctl 'make' m

For zsh, you can create a new completion with compdef function.
In its basic form it associates a completion function with a word. Provided that zsh comes with lots of completions already built-in, one can just reuse those. For example, for m function from the question:
$ compdef _make m
As per documentation, you can also define a completion for a specific service, if the one is defined in the completion function. Again, as zsh comes with _git completion and it already defines git-log service, a gl function from the question may be autocompleted with:
$ compdef _git gl=git-log
On Linux, you can see existing completion implementations in /usr/share/zsh/functions/Completion/Unix/. You can read the completion implementations to see what services they define.

Related

fish shell + omf + git plugin: how to customize the prompt in the terminal

I have fish shell with omf with agnoster theme and git-plugin installed.
I would like to tune my prompt a bit. Does anyone here know where/how I do that. I ran fish_config; but that did not show my current prompt properly. So I am reluctant to go that route. I would rather do it by typing it in; but can't figure out where the final prompt is being stored. I tried 'echo $fish_prompt'. Did not help.
Would appreciate some help. Thanks!
fish_prompt is a function. See https://fishshell.com/docs/current/cmds/fish_prompt.html. To see where it is defined run functions --details fish_prompt. There is no "final prompt [is] being stored" as I understand that phrase. There is a function that creates the prompt. Your echo $fish_prompt would only output something useful if the prompt was a literal string (which isn't supported). You can use functions --all fish_prompt to see where it is defined and the content of the function.
When I used Fish I did not use OMF (I'm now an Elvish user). I had a custom function defined in ~/.config/fish/functions/fish_prompt.fish. So I can't explain how to customize the OMF "agnoster" theme prompt. You'll need to read the documentation for that theme to learn what knobs, if any, it provides for customizing its behavior.
Short answer: edit function fish_prompt in file: .local/share/omf/themes/agnoster/functions/fish_prompt.fish.
Explanation:
This exact file may not work in cases with different plugin's and/or different theme.
The way I figured this was to search for all "*prompt.fish" functions in my home directory. Put a distinct print statement with the prompt in each one of them and check which one got printed and modified the fish_prompt.fish function in that file - which is working for me!

Fish shell git_prompt inside TIDE

Is it possible to force Fish shell extention TIDE to
use fish_git_prompt instead of its own _tide_item_git.fish?
My goal is to make TIDE git prompt identical to this tutorial.
Right now with default TIDE setting I have this git prompt:
However, I want to make it look like this, but still use TIDE:
Source image
fish, version 3.2.1
Fedora 33
So what that tide function does is simply collect the git info and print it. Tide calls it, takes what it prints, and puts it in the correct place. This is also how the fish_git_prompt works - it prints the git stuff, your prompt is responsible for putting that in the correct place.
Simplified:
function fish_prompt
set gitstuff (_tide_item_git)
# do other tide stuff
printf '%s' $gitstuff $otherstuff
end
When fish calls a function, it goes through $fish_function_path for a file with the name of the function (plus a ".fish" suffix).
So what you would simply do is make your own function _tide_item_git, and put it first in $fish_function_path.
I'm not sure how you've installed tide, I'm assuming it's not directly in ~/.config/fish/functions - the normal directory for your functions. That's the simple case, so you can just call funced _tide_item_git, which will open it in your editor, and replace it with
function _tide_item_git
fish_git_prompt
end
then run funcsave _tide_item_git once you're happy.
In the more complicated case, make another directory for your functions - ~/.config/fish/myfunctions maybe - add it to $fish_function_path:
set -g fish_function_path ~/.config/fish/myfunctions $fish_function_path
(put that in config.fish)
make a file called _tide_item_git.fish there and put the above function in.

Enable returning multiple arguments as completion reply at once in fish shell

I am working on porting Google Cloud SDK command line auto completion feature to fish shell. When I have an unambiguous reply with multiple arguments:
A) Either the command is completed with all those arguments BUT spaces gets escaped (\ ) when I specify the function call in the complete command inside ''s or ""s, like: > complete ... -a '(__fun)'
B) or if I don't do that (just: -a (__fun)), then only the first argument of the reply gets into the completion and all the other arguments "get lost"
Is it possible to reply with multiple arguments at once in fish completion?
Could be done in a number of ways. You will have to hack it a bit, though, since as ridiculous_fish says it's not designed for this.
Easiest would be to ship your own wrapper function that can take the escaped output and pass it on in a way that works. Not very pretty, though, and would screw with autosuggestions unless you also go back and modify the history lines.
Here's something semi-hacky/semi-elegant I would propose:
If you have looked up a "sequence" of args you'd want to complete at once, at first invocation put the trailing args as the description to the first one. Once that one has been locked in, remove all other options but the first in this "description queue", keep going through it and it will simply be a matter of quickly pressing tab-tab-tab-tab.
Completions don't have to be perfect, they're mostly a lil help on the way until you have enough history lines that autosuggestions take over, imo.

How to force filename completion under oh-my-zsh?

The problem:
Sometimes, when I try to do things in zsh, it won't complete the filenames I want because they don't apply to the current context. Two examples:
I want to force-add a file which is currently ignored in hg or git. oh-my-zsh tries to help me by only completing non-ignored files, but in this case it is a hindrance. I'm forced to type the full path to the file manually.
I want to use git diff to diff two arbitrary files on my hard drive. These files do not reside in any repository, but who cares?! git diff --no-index is a really nice way to diff any two files. But because they aren't in a repo, zsh won't complete them.
The proposed solution:
I could simply edit the source control context to complete all filenames, regardless of their source control status. But there are a couple limitations:
I don't know how to do that.
It might be nice to have an "escape hatch" whereby I could force file completion, no matter what the context.
So, I decided instead to bind a key shortcut to force normal, context-free file completion.
What I have so far:
Zsh apparently has an easy way of doing this, as detailed in this question. So I've added the following lines to my .zshrc:
zle -C complete complete-word complete-files
bindkey '^[[Z' complete
complete-files () { compadd - $PREFIX* }
This causes shift-tab to initiate file completion. It works beautifully in standard zsh! But boo-hoo, for some reason it doesn't work when I source oh-my-zsh. :-(
So is there a way to get this to work with oh-my-zsh, or is there an alternative solution I might find satisfying?
My way of doing exactly that (replacing the default diff command with the one from git) was pretty straightforward.
Add this to your ~/.zshrc:
diff() {
git diff --no-index "$#"
}
Before I was using an alias, but since zsh can "solve" them, it was then using the autocompletion functions from git diff, which inadvertently led to the same problem as you.
Using a function solves this issue as zsh reverts to the classic "files only" completion.

How can one provide colour to tab completion in tcsh?

(Crossposted to unix.stackexchange.com)
This question and the answer teach us how to introduce colour into tcsh prompts.
This webpage explains nicely how to get colour into any output of the echo command:
> echo \\e[1\;30mBLACK\\e[0m
BLACK
> echo '\e[1;30mBLACK\e[0m'
BLACK
The word 'BLACK' in the example above is printed with a black (or darkgrey) foreground colour (depending on the overall color scheme).
Now I'd like to introduce this into the [TAB] command autocompletion feature of tcsh. I tried:
complete testcmd 'p/*/`echo '"'"'\e[1;30mf834fef\e[0m'"'"'`/'
And I get:
> testcmd [TAB]
> testcmd ^[\[1\;30mf834fef^[\[0m
Obviously the characters lose their special meaning. Hopefully I just did not get the escaping right. But I tried several other ways. So any help is appreciated.
The real use case is that I've got a command completion that offers three different types of completions and I'd like to visually distinguish the types. Also the alternatives are computed by an external command. That is why I need the completion to use the backticks with an external command, such as echo. I don't care about the details of this command. If you make it work in any way with the tcsh's complete command I'll probably be able to adapt (thinking perl -pe wrappers and such).
The reason why I believe this has to work somehow is that the tcsh itself offers coloured command completion if you e.g. type ls [TAB]. That works correctly in my setup. Also you can use ls -1F inside the autocompletion and the colours that ls outputs are also piped through. An example would be:
complete testcmd 'p/*/`ls -1F`/'
Update: As user mavin points out, the colourization of ls in this example is indeed not piped through. The colours of ls are lost, but the auto completion can reapply colours according to LS_COLOURS variable based on hints such as the / and * marker endings as added by the ls. This can be verified by doing
complete testcmd 'p/*/`ls --color -1`/'
which fails to provide colour, and only provides garbled output. (Literally pipes through the escape character sequences)
I'm on tcsh version 6.13.00
Any ideas? Pointers?
In your example, complete testcmd 'p/*/ls -1F/', the colours aren't getting passed through from ls. You'll find that you get colour here even if you set ls to produce monochrome output, but not if you leave off the -F. What's happening is that tcsh is doing its own colouring based on the symbols added to the end of each filename by ls -F. For example:
complete testcmd 'p%*%`echo dir/ symlink# device# socket=`%'
You could exploit this in your completion generator, e.g.,
complete testcmd 'p/*/`echo foo bar | perl -lane '"'"'print join " ", map { $_. "%" } #F'"'"'`/'
The snag is that you end up with these symbols in your completed command-line, and will have to manually backspace each time.
tcsh will colour filenames based on their suffix, dependent on the $LS_COLORS environment variable (e.g., show all *.gz files in red). You could pre-calculate the list of potential completions, place them all in $LS_COLORS, then set up dummy files for the completion to use. If you use the precmd alias, you can have the completions automatically recalculated every time the prompt is shown.
complete testcmd "p#*#F:$HOME/.cache/testcmd-completions#"
alias prep-testcmd "setenv LS_COLORS '*red=01;31:*green=01;32:' && rm -r ~/.cache/testcmd-completions && mkdir -p ~/.cache/testcmd-completions && touch ~/.cache/testcmd-completions/red ~/.cache/testcmd-completions/green"
alias precmd prep-testcmd
Aside: it'd be nice to use this with a ``-style completion rather than an F-style completion; that way you wouldn't need to create the dummy files. However, I tried that in tcsh 6.17 and it didn't work.