How can one provide colour to tab completion in tcsh? - autocomplete

(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.

Related

Tab-complete herbstclient with fish shell?

I'd like to be able to simply type herb and then press tab and have fish-shell tab-complete it to herbstclient. I've tried looking it up, but every result I can find has to do with overiding fish's autocomplete with tab rather than ctrl + f.
Do I need to create a fish script for this? If so, what should it look like and where should I put it?
Assuming that is a command you want an abbreviation: abbr herb herbstclient. Although you don't use [tab] to complete an abbreviation; you have to press [space] or [enter]. Note that the expansion can consist of multiple tokens. For example, this is one of my most often used abbreviations: abbr -a -g -- gcm 'git checkout master'. Also, abbreviations only get expanded in the command position; i.e., start of line or after a pipe, |, or semicolon. If you want that expansion elsewhere in a command line there are ways to achieve that but it's a bit more complicated.

iPython-like completion for zsh?

I wonder if there's a way to use ipython-like completion in zsh?
What I mean is in ipython you could type several characters and then loop through your command history, but this will only affect those commands which start with characters you've typed in the first place.
If your history look like this:
token = 'something blah blah'
import os
token.split()
..and then you type token and loop through history in ipython you will get only 1st and 3rd lines.
So is there any way to make zsh work this way?
You can use the widgets history-beginning-search-backward and history-beginning-search-forward for that. By default they are not bound to any keys so you'll have to do that with bindkey.
bindkey "^[[5~" history-beginning-search-backward
bindkey "^[[6~" history-beginning-search-forward
Where ^[[5~ is the code for page up and [[6~ for page down. These codes may be different for your terminal.
You can either use cat -v to show the codes for the non-printing characters. Or you can use the associative array terminfo from the zsh/terminfo module (which may already be loaded; see zshmodules(1) and zshbuiltins(1) for more infos on zsh modules) which should contain the correct codes in the keys knp (next-page key) and kpp (previous-page key):
if (( ${+terminfo[knp]} )) && (( ${+terminfo[kpp]} )); then
bindkey "${terminfo[kpp]}" history-beginning-search-backward
bindkey "${terminfo[knp]}" history-beginning-search-forward
fi
To be honest these widgets will not loop when they reach the beginning or end of history, but as you can go both directions (and considering that ipython does not loop either) that should not be a real problem.

Matlab-like command history retrieval in unix command line

In Matlab, there is a very nice feature that I like. Suppose I typed the command very-long-command and then a few several commands afterwards. Then later if I need the long command again, I just type very and press the up arrow key, my long command appears. It finds the last command that starts with very. I couldn't do the same in unix command line, when I try to do it, it disregards whatever I typed, and goes back to the last commands in chronological order. Is there a way to do it?
In bash this functionality is provided by the commands history-search-forward and history-search-backward, which by default are not bound to any keys (see here). If you run
bind '"\e[A":history-search-backward'
bind '"\e[B":history-search-forward'
it will make up-arrow and down-arrow search backward and forward through the history for the string of characters between the start of the current line and the point. See also this related Stack Overflow question.
In bash, hitting ctrl-r will let you do a history search:
$ echo 'something very long'
something very long
$ # blah
$ # many commands later...
(reverse-i-search)`ec': echo 'something very long'
In the above snippet, I hit ctrl-r on the next line after # many commands later..., and then typed ec which brought me back to the echo command. At that point hitting Enter will execute the command.
You can do the same thing by using "!". For example:
$ echo "Hello"
Hello
$ !echo
echo "Hello"
Hello
However, it is generally a bad idea to do this sort of thing (what if the last command did something destructive?). If you expect you will reuse something, then I suggest you create a shell script and save it away somewhere (whenever I plan to reuse something, I create a script in ~/.local/bin).

How can I script vim to run perltidy on a buffer?

At my current job, we have coding-style standards that are different from the ones I normally follow. Fortunately, we have a canned RC file for perltidy that I can apply to reformat files before I submit them to our review process.
I have code for emacs that I use to run a command over a buffer and replace the buffer with the output, which I have adapted for this. But I sometimes alternate between emacs and vim, and would like to have the same capabilities there. I'm sure that this or something similar is simple and had been done and re-done many times over. But I've not had much luck finding any examples of vim-script that seem to do what I need. Which is, in essence, to be able to hit a key combo (like Ctrl-F6, what I use in emacs) and have the buffer be reformatted in-place by perltidy. While I'm a comfortable vim-user, I'm completely clueless at writing this sort of thing for vim.
After trying #hobbs answer I noticed that when filtering the entire buffer through perltidy the cursor returned to byte 1, and I had to make a mental note of the original line number so I could go back after :Tidy completed.
So building on #hobbs' and #Ignacio's answers, I added the following to my .vimrc:
"define :Tidy command to run perltidy on visual selection || entire buffer"
command -range=% -nargs=* Tidy <line1>,<line2>!perltidy
"run :Tidy on entire buffer and return cursor to (approximate) original position"
fun DoTidy()
let l = line(".")
let c = col(".")
:Tidy
call cursor(l, c)
endfun
"shortcut for normal mode to run on entire buffer then return to current line"
au Filetype perl nmap <F2> :call DoTidy()<CR>
"shortcut for visual mode to run on the current visual selection"
au Filetype perl vmap <F2> :Tidy<CR>
(closing " added to comments for SO syntax highlighting purposes (not required, but valid vim syntax))
DoTidy() will return the cursor to its original position plus or minus at most X bytes, where X is the number of bytes added/removed by perltidy relative to the original cursor position. But this is fairly trivial as long as you keep things tidy :).
[Vim version: 7.2]
EDIT: Updated DoTidy() to incorporate #mikew's comment for readability and for compatibility with Vim 7.0
My tidy command:
command -range=% -nargs=* Tidy <line1>,<line2>!
\perltidy (your default options go here) <args>
If you use a visual selection or provide a range then it will tidy the selected range, otherwise it will use the whole file. You can put a set of default options (if you have any) at the point where I wrote (your default options go here), but any arguments that you provide to :Tidy will be appended to the perltidy commandline, overriding your defaults. (If you use a .perltidyrc you might not have default args -- that's fine -- but then again you might want to have a default like --profile=vim that sets up defaults only for when you're working in vim. Whatever works.)
The command to filter the entire buffer through an external program is:
:%!command
Put the following in ~/.vimrc to bind it to Ctrl-F6 in normal mode:
:nmap <C-F6> :%!command<CR>
For added fun:
:au Filetype perl nmap <C-F6> :%!command<CR>
This will only map the filter if editing a Perl file.
Taking hobbs' answer a step further, you can map that command to a shortcut key:
command -range=% -nargs=* Tidy <line1>,<line2>!perltidy -q
noremap <C-F6> :Tidy<CR>
And another step further: Only map the command when you're in a Perl buffer (since you probably wouldn't want to run perltidy on any other language):
autocmd BufRead,BufNewFile *.pl,*.plx,*.pm command! -range=% -nargs=* Tidy <line1>,<line2>!perltidy -q
autocmd BufRead,BufNewFile *.pl,*.plx,*.pm noremap <C-F6> :Tidy<CR>
Now you can press Ctrl-F6 without an active selection to format the whole file, or with an active selection to format just that section.
Instead of creating a new keyboard shortcut, how about replacing the meaning of the = command which is already in people's finger memory for indenting stuff? Yes, perlcritic does more than just indent but when you use perlcritic anyways, then you probably don't want to go back to the inferior "just indent" = command. So lets overwrite it!
filetype plugin indent on
autocmd FileType perl setlocal equalprg=perltidy
And now we can use = just like before but with the added functionality of perlcritic that goes beyond just indenting lines:
== run perlcritic on the current line
5== run perlcritic on five lines
=i{ Re-indent the 'inner block', i.e. the contents of the block
=a{ Re-indent 'a block', i.e. block and containing braces
=2a{ Re-indent '2 blocks', i.e. this block and containing block
gg=G run perlcritic on the entire buffer
And the best part is, that you don't have to learn any new shortcuts but can continue using the ones you already used with more power. :)
I'm used to select text using line oriented visual Shift+V and then I press : an I have !perltidy -pbp -et4 somewhere in history so I hit once or more up arrow ⇧.

Is there a way to display a macro list similar to displaying your mappings in Vim?

I know there is a way to list mappings via :map (or :imap, :cmap, etc.), but I can't find a way to list macros I have stored in my vimrc file (as in let #a = 'blahblah').
Is there a way to do this without having to manually looking inside it (via :split [myvimrcfile] or whatever way)?
Also, if it is possible, is there a way to attach some sort of documentation that would display with the macro to explain what it is for? I have a handful that I use quite a bit, but about 6 weeks apart. It would be nice to just quickly list them along with a comment that tells me what the macro does (or even just a name so I make sure I use the right one).
Thanks
In vim, the macros are just stored in registers. You can recall the content of any register and execute it as a macro (which is what the # does). To see a list of what is in your registers, use :reg.
You can see the contents of all the registers using the
:reg
command. Or an argument string like this
:reg ahx
will show you the contents of registers a, h, and x.
That way you can at least see what sequence of commands will be run and hopefully that will be clear enough for you to tell one from another.
The registers simply contain text. You can paste the command sequence in as text or you can copy text into a register and then run it as a command, depending on how you access the register.
I have not found any direct way to edit the contents of a register, but you can paste it into the file, edit it, and then save it back to the same register.
IHTH.
As /u/jheddings wrote the macros are stored as registers and what counts is the assignment of the code to the register (usually done in the vimrc files with let #a=blahblah
To ease the way to display the macros you defined in your vimrc file (in my case it is in the ~/.vimrc path) you can use this vim function:
function! ShowMacros()
10new
exe 'r!' . 'grep -B 1 -E "^\s*let #" ~/.vimrc'
call cursor(1,1)
endfunction
What it does:
10new - open a new vim window with ten lines size
exe ... - execute a command and put in the window
call ... - go to the first line first column
You can execute this function by tipping in the normal mode
:call ShowMacros
You could additionally create a key mapping or a command to fasten the way to call the function:
:cnoremap sm call ShowMacros()<CR>
command! sm call ShowMacros()`
This is the original post where I wrote the function similar to the above.
The OP asked, "is there a way to attach some sort of documentation that would display with the macro to explain what it is for?"
I have found VI / VIM macros extremely obtuse to understand even a week after I've written them, so I heartily support the idea of documentation. I have a suggestion for that, in two parts.
First is the process of documenting the macro in your .vimrc. I've developed the following .vimrc comment format that helps me understand, a week or a year or more later, what a macro is supposed to be doing. E.g.:
"
"= GENERIC CLIPBOARD YANK <F2>y (Y for Yank)
"= Yank the entire contents of the file into the clipboard; quit without saving.
"
"define F2 followed by y to be:
"| Go to line 1.
"| | From there, into the * buffer (system clipboard),
"| | | yank to the end of the file.
"| | | | Go to sleep for 1 second (to allow the clipboard to be updated).
"| | | | | Quit without saving the file.
"| | | | | |
map #2y 1G"*yG1gs:q!<CR>
"-------"-"-"-"--"------
Second, I am imagining that Jakub's ShowMacros() function above could be modified to grep a specific set of Help lines for each macro that would be in the file along with the definition, much the way the above command-line breakdown is attached to the definition, that would provide the needed User Help.
I've flagged two lines above with "= at the beginning of each, so that they can become the User Help. Then Jakub's grep command would search for "^\"= ". Here's the command I used. I'm not sure if the -E for Extended Regular Expressions is needed and the -B 1 is a nice touch to include one line previous to a matching sequence, so here I have an explicitly empty comment line.
In my vimrc, I only needed one backslash, for the initial parsing of the definitions. Here's the line, replacing the one in Jakub's function definition above:
exe 'r!' . 'grep -B 1 -E "^\"= " ~/.vimrc'
Thanks to Jakub's hint, I now can generate help from my .vimrc in pretty much exactly the way the OP is asking for. I've been using vi since 1983, so I'm pretty stoked.
Thanks Jakub!
IHTH,
August