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

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

Related

Move to specific line and column in one command

Let's say we have a text file that is very long and has many lines. I want to move to 30th line and 15th column in this file.
Are there any VIM commands that could be used to move to mentioned line number and column in one command? Thanks.
Please, do not suggest to use smt like :30 command and after 15| this is NOT an option.
May VIM has an option to input smt like: :30,15, just in another syntax?
The only option I found is to use :call cursor(30,15) but it looks little bit too long, as I need to type it each time I want to jump to the another position.
You can define your own command-line command. Define it in ~/.vimrc and it will be available everywhere. Define:
:command -nargs=* Go call cursor(<f-args>)
Run:
:Go 30 15
Well, you want to move across two dimensions but Vim commands are limited to one dimension, therefore you can't move to line 30 and column 15 with a single built-in command.
Here are the shortest key sequences to move to column 15 of line 30:
" in normal mode
30G15|
" in command-line mode and normal mode
:30<CR>15|<CR>
" in command-line mode
:30norm15|<CR>
" from the shell
$ vim foo.txt +norm30G15\|<CR>
Note that the first suggestion above is already the shortest theoretically possible sequence because you would need:
at least one key for the command itself,
at least one key to separate the two coordinates,
the vertical coordinate (can't be shortened),
and the horizontal coordinate (can't be shortened).
The only improvement I can think of to 30G15| would be to use keys that don't require a modifier but, frankly, I am not sure that it is worth the hassle.

Emacs: How to read command help just as one would read Man pages?

It's nice to run M-x man foo for command foo within Emacs. It's then possible to navigate easily within the man page and to find details quickly.
When the help of a command (such as git) produces limited output, one can just use a terminal instead of emacs.
But occasionally, a command (such as aws help—run in a terminal) produces extensive output. Yet the output is not compatible with the emacs Man mode. An option is to use M-x shell within emacs, but that will not display the page at once. It will report "WARNING: terminal is not fully functional" and require pressing a key endlessly until the complete help appears, or, for Emacs 25, "Could not find executable named 'groff'".
What is a good way to read long manual pages produced by commands within emacs?
I just ran into this exact problem a few days ago.
Type escape + ! then type (for example) “aws ec2 help”. This brings the help text into a new buffer called Shell Command Output, with all of the control-h characters, etc.
Switch to the new buffer with control-x then lowercase ‘o’ (for other buffer)
Type escape + lowercase ‘x’ to run an emacs function, then type ‘man’ and hit Enter. It will prompt for man page entry and default to EC2, just hit Enter. In my case, it displays an error in the status line, “error in process sentinel: Can’t find the EC2 manpage”.
However, the “man page” functions are now available, so now (in that buffer)you can type escape + x and run the function Man-fontify-manpage. The page should now look like a nice man page with bold, etc.
You can then rename the buffer (escape + x then something like ec2) so the buffer isn’t replaced if you run another shell command.
I you just want the output in a buffer, you can simply use:
M-! aws help RET
If you want the output in a shell buffer, you can do git help commit | cat (so no more "terminal is not fully functional").
Probably you can do M-! aws help | cat RET also. I do not have aws, but hopefully the piping will remove the escape characters if aws output formatting is done right. You should try also TERM=dumb aws help. Any command should know better than using fancy output when TERM is set to dumb. If aws is dumb that way itself, you could pipe its output to something that filters out control characters -- try this
For forcing man mode in an arbitrary buffer, M-x Man-mode (yes, uppercase). I am not sure if that will play nice with aws's output.
By the way, for git I suppose you know you can do man git-commit (or man git-any_git_command, in general), so you have a nice alternative to git help when using emacs (output of help and man page is the same).

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.

How can I modify emacs' Search and Replace to perform a more complicated task?

total Emacs noob here. So right now I'm working on a fairly big LaTeX project in Emacs in which there are couple of places where I need to index some words, using the makeidx package. Because I also wanted indexed words to be bold, I created my own command \ind{} which would make the argument go bold and indexed. But right now I'm dissatisifed with this command so I'd like to change every instance of \ind{whatever} in my text by \textbf{whatever}\index{whatever by default}.
The thing is I know exactly what I want :
Go through the text, look for any instance of \ind{ and replace by \textbf{ using search-and-replace
Save the argument of \ind ("whatever" in this case) in memory
Ask me the user what should the argument of \index be. By default (by striking enter), it should be the first argument, but I can also change my mind and enter something different ("whatever by default" in this case). If there's no input (only a space " " for example) stop the program.
Write down \index{, the new argument and }.
Go to next occurance in the text.
But, alas!, I know not how to achieve this, so I need someone's help. If it should take too much time to explain how to do such a thing, would you please send me some tutorial about writing my own functions?
I hope I'm being clear, and thanks for your patience!
This approach seems vaguely unorthodox to me, but it works and seems sufficient for a one-off job...
In the replacement text for replace-regexp and query-replace-regexp (C-M-%), one newer escape sequence is \,(...), where ... can be any Lisp expression. There's a Lisp function read-from-minibuffer which reads arbitrary text typed by the user, with an optional default. Therefore:
C-M-%: Start query-replace-regexp.
\\ind{\([^}]+?\)}: The pattern to search for.
\\textbf{\1}\\index{\,(read-from-minibuffer "index content? " \1)}: The replacement text. The user will be prompted for the text to put in the braces following the \index{} element, using the original text between the braces following the \ind{} element as a default.
Note that when using query-replace-regexp, you'll have to confirm each choice by typing y after each. Use M-x replace-regexp if you want to avoid this step.
Vlad give you the LaTeX answer to your problem. An Emacs solution is the key-macro: start with
C-x (
to define a new macro, then do one step of your change, say:
C-s \ind{
<left>ex
Then copy and paste the argument in the \textbf macro... You have to be careful to move in a way that will be repeatable. Once the standard modification is done, you let the cursor after the whatever by default and end the definition by
C-x )
now C-x e will call the macro you just define, letting your cursor at the correct place to change the part you want to change You can also repeat the e to call the macro several time at once.
Why not just redefine the \ind so that it can get an optional argument?
For example:
\newcommand{\ind}[2][]{%
\def\first{#1}%
\ifx\first\empty
\textbf{#2}\index{#2}%
\else
\textbf{#2}\index{#1}%
\fi
}
This way you can use \ind{whatever} or \ind[whatever-else]{whatever}.

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