Vim macro: log/variableize selected object - vim

Is there some sort of Vim plugin that would allow me to do something like this, given the code:
function something (arbitraryObject) {
arbitraryObject.something = doesNotMatter;
}
Then let's say I just select the word arbitraryObject in the function body, I'd like an easy way to write a macro that, given a short key combination or command-mode command, could give me something like:
function something (arbitraryObject) {
arbitraryObject.something = doesNotMatter;
console.log(arbitraryObject);
}
or...
function something (arbitraryObject) {
arbitraryObject.something = doesNotMatter;
window.arbitraryObject = arbitraryObject;
}
Note that I'm not asking what this macro would actually look like, I'm curious if there are built-in tools or plugins that make the creation of things like this particularly easy.

I know that you aren't asking for the specific macro, but it's easiest to learn these types of things by example. The first one (console.log) can be achieved through this mapping:
:vmap <leader>il y<esc>oconsole.log(<c-r>");<esc>
Likewise, the second one could look like this:
:vmap <leader>iw y<esc>owindow.<c-r>" = <c-r>";<esc>
Can you spot the similarities? <leader>il means that the command binds to the leader key (usually ,) followed by i followed by l. You can check what the following commands mean by using :help [key] in vim, but the mappings basically yank (copy) the selected text, enters a new line (Esc, o) and then appends some text followed by Ctrl+r and ", which inserts the yanked text.

One option would be to use something like snipMate.vim and have snippets for your various tasks. For example, you could create these snippets:
snippet cons
console.log(${1:variable});${2}
snippet wind
window.${1:attribute} = $1${2}
Then you could do something like yocons<Tab><C-r>"<Tab>, or likewise yowind<Tab><C-r>"<Tab>. You could also use yiw instead of visually selecting too. I like an option like this because then you can easily make it applicable to only a particular type of filetype (e.g. javascript) and continue to extend your already existing snippets.

nmap <Leader>l o<esc>pv^"xygv[ygvdiconsole.log(<esc>a"<esc>pa",<esc>"xpa);<esc>
This is better alternative, since it quotes strings with help of vim-unimpared. Just yank text, you need to log and use this key binging. It converts
this.$el.find("input,select,textarea")
to
console.log("this.$el.find(\"input,select,textarea\")",this.$el.find("input,select,textarea"));

Related

Vim Custom Replace Function

Note: I'm currently using Neovim v0.2.2 (But I believe this shouldn't change anything related this post)
I'm currently attempting to create a function within vim that allows for easily replacing text.
I understand I can create a shortcuts and macros and all that, but ideally I just want to give 2 args, and not think about what specifics go where as this can interupt my thought process.
So I decided to just have a simple wrapper disguised as a function (Which I will create a command wrapper for as well, once I figure out what I did wrong here)
function! VisualReplace(query, replacement)
" Example = '<,'>s/query\%V/replacement/g
'<,'>s/a:query\%V/a:replacement/g
endfunction
As you can see, it's a very simple function that just applies the args in it's respective position, Yet, this fails even when called as a function using : call VisualReplace('some_query', 'some_replacement'
Alternatively, if you simply use the Example I have commented out directly, there's no issue, So I was hoping someoen could enlighten me on a potential fix
If need be, I could possibly look into string building & build it incrementally
Error msg:
Pattern not found: a:query\%V
General theory
Vimscript is evaluated exactly like the Ex commands typed in the : command-line. There were no variables in ex, so there's no way to specify them. When typing a command interactively, you'd probably use <C-R>= to insert variable contents:
:sleep <C-R>=timetowait<CR>m<CR>
... but in a script, :execute must be used. All the literal parts of the Ex command must be quoted (single or double quotes), and then concatenated with the variables:
execute 'sleep' timetowait . 'm'
Your function
In order to get the a:query and a:replacement arguments into :substitute, use :execute and either string concatenation or printf():
function! VisualReplace(query, replacement)
execute "'<,'>s/" . a:query . '\%V/' . a:replacement . '/g'
endfunction
Additional critique
Passing a range to a function is so common, there's special syntactic sugar for it: The range attribute to :function, and a:firstline and a:lastline implicit arguments. Read more about it at :help function-range-example. While your use case here seems to be specifically for visual mode, in general it's useful to keep the scope of functions as broad as possible.
#Ingo Karkat answered perfectly. However, I feel like there might be some workflow alternatives which might help. (Assuming you aren't trying to script this behavior)
Visual Star
It looks like you are build a search based on a visual section. You may want to consider using a visual-star plugin to simplify the process. Here is a an example of a visual star mapping:
xnoremap * :<c-u>let #/=#"<cr>gvy:let [#/,#"]=[#",#/]<cr>/\V<c-r>=substitute(escape(#/,'/\'),'\n','\\n','g')<cr><cr>
This mapping will allow you to visually select text and then execute * to make it a search pattern. Similar to how * works in normal mode on the current word.
Search refining
I get the impression that you are trying to refine your search pattern. Vim has a nice way of doing this with q/ or pressing <c-f> while searching with /. See :h q/. This will bring up the command-line window which will allow you to edit the query/command-line with all your normal Vim keys.
Search and Replace with gn motion
Sometimes doing a substitution is just overkill or doesn't quite fit the situation right. You can mimic a search and replace by using the gn motion to operate on a search pattern. By using an operator and the gn motion together you can use the dot command, ., to repeat the action easily.
Example:
/foo
cgnbar<esc>
Now you can use . to repeat the foo -> bar replacement. Use n to skip. You can use other operators as well, e.g. gU to uppercase.
See :h gn and :h operator for more help.
Related Vimcasts episodes:
Refining search patterns with the command-line window
Operating on search matches using gn
Search for the selected text

How to commentize a word in Vim?

I would like to commentize a word under the cursor and use it as a macro or map it as a key binding.
For example this:
void somefunc(MyType* pType);
Would become:
void somefunc(MyType* /*pType*/);
I know that I just need to prepend and append word with /* and */ but I dont know how to do this.
try either of this mapping, pick one you feel better.
nnoremap <leader>cw caw/*<c-o>P*/<esc>
or
nnoremap <leader>cw viw<esc>a*/<esc>hbi/*<esc>
type <leader>cw in normal mode.
A way more general way to create inline comments is to use the Tcomment plugin.
When you've installed it you can use the gc operator to comment something, for example if you have the following file (with ^ indicating the cursor):
void somefunc(MyType* ^pType);
Pressing gce will get you:
void somefunc(MyType* /*pType*/);
You can use this for any motion command, but of course a line wise operator (eg. gcj) will not comment inline but entire lines instead.

Vim Visual Select around Variables

I'm wondering if there's a way to select variables intelligently in the same way that one can select blocks using commands like va}. There's some language-specific parsing going on to differentiate php and ruby, for example. For future reference, It'd be nice to tap into that - ideally selecting around various syntactic elements.
For example. I'd like to select around $array['testing'] in the following line of php:
$array['testing'] = 'whatever'
Or, lets say I want to select the block parameter list |item, index| here:
hash.each_with_index { |item, index| print item }
EDIT:
Specific regexps might address the various questions individually, but I have a sense that there ought to be a way to leverage syntactic analysis to get something far more robust here.
Though your given examples are quick to select with built-in Vim text objects (the first is just viW, for the second I would use F|v,), I acknowledge that Vim's syntax highlighting could be a good source for motions and text objects.
I've seen the first implementation of this idea in the SyntaxMotion plugin, and I've recently implemented a similar plugin: SameSyntaxMotion. The first defines motions for normal and visual mode, but no operator-pending and text objects. It does not skip over contained sub-syntax items and uses same color as the distinguishing property, whereas mine uses syntax (which can be more precise, but also more difficult to grasp), and has text objects (ay and iy), too.
You can define your own arbitrary text objects in Vim.
The simplest way to do custom text objects is defining a :vmap (or :xmap) for the Visual mode part and an :omap for the Operator-pending mode part. For example, the following mappings
xnoremap aC F:o,
onoremap aC :normal! F:v,<CR>
let you select a colon-enclosed bit of text. Try doing vaP or daP on the word "colon" below:
Some text :in-colon-text: more of the same.
See :h omap-info for another short example of :omap.
If you don't mind depending on a plugin, however, there is textobj-user. This is a general purpose framework for custom text objects written by Kana Natsuno. There are already some excellent text objects written for that framework like textobj-indent which I find indispensable.
Using this you can easily implement filetype-dependent text objects for variables. And make it available for everybody!

vim: pass a char or word to your function

I know that when you define a function in vim, you can use the range keyword so that users can say:
:-5,+5call MyFunction()
And then your function gets a:firstline and a:lastline.
What I want is something similar, but more like the traditional vi way of combining a command with a movement, so that 'd ' deletes a space, 'dw' deletes a word, 'd2w' deletes two words, 'd2j' deletes three lines, etc. Assuming my function gets mapped to some input-mode character sequence, is there any way to make it accept similar variable-length inputs, and then modify that text?
Just to be a little more clear, suppose I want to define a function to wrap <b> tags around existing text. We'll say that function is mapped to ;b. I want users to be able to say ';bw' to bold one word, or ';bf.' to bold everything to the end of the sentence, or whatever, with all the flexibility that vim provides to built-in commands.
If I understand what you're asking, then all you do is include the char argument in your mapping. For example:
map d :call MyFunction('d')<cr>
map dw :call MyFunction('dw')<cr>
map d2w :call MyFunction('d2w')<cr>
" Of course these would be terrible mappings because they
" are already mapped to important Vim functions
The way mappings work is that if you "overspecify" a char like 'd' above so that it is usable either by itself or as a prefix for longer command, Vim will wait briefly (for timeoutlen)after you press 'd' to see if you're going to press another character. (This depends on thetimeout option being set to true, which is the default.) If you don't press another character, Vim will execute the 'd' mapping. If you do it will call the more complex mapping. See :h map-commands generally and :h map-typing for more.
Note: After your clarification I think what you want is to create a custom 'operator' function that you can use to operate on buffer areas defined by Vim motions. See :h map-operator for info on how to do this.

Is there a "verbatim" mode for the vim map command?

I am trying to set up some useful coding templates in vim, for example I have mapped
map `cl iclass <+CLASSNAME+><CR>{<CR><Esc>Iprotected:<CR><+PROTECTED MEMBERS+><CR><Esc>Ipublic:<CR><+PUBLIC INTERFACE+><CR>};<CR><++><CR><Esc>3kv<0v3k<2k
so that when I type `cl in vim I get
class <+CLASSNAME+>
{
protected:
<+PROTECTED MEMBERS+>
public:
<+PUBLIC INTERFACE+>
};
<++>
(so that I can jump between the <+ +> tags with C-j). This works fine, but I find the above remap pretty obscure. Is there a way to enter what I want vim to type in "verbatim mode"? So I would want to write something like
map `cl i{VERBATIMSTART}class <+CLASSNAME+>
{
protected:
<+PROTECTED MEMBERS+>
public:
<+PUBLIC INTERFACE+>
};
<++>{VERBATIMEND}
?
Thank you
Paul
I don't know if there is such a "verbatim"-mode for mappings.
I, personally, would use one of the snippet-plugins to do this.
See www.vim.org and search
for "snippet". I have not tried all of them (just SnippetsMgr ;-) ),
but I suppose that they are handier to define multi-line-snippets.
Some of the available snippet-plugins on vim.org: snippets.vim ,
snippetsEmu, snipMate, SnippetsMgr, etc.
As Habi has mentioned, one way to go about this is with a snippet plugin.
Another way is to copy that snippet of code into its own file and set up your mapping to insert that file below the cursor:
map `cl :r /path/to/code_snippet<CR>
Kind of obvious (and probably not what you want) is:
map `cl iclass <+CLASSNAME+>
\<CR>{
\<CR>protected:
\<CR> <+PROTECTED MEMBERS+>
\<CR>public:
\<CR> <+PUBLIC INTERFACE+>
\<CR>};
\<CR><++>
\<CR>
\ in beginning of line tells that the line is the continuation of the previous one. But this is rather literal continuation: it doesn't add new lines so one has to add them manually. Since it uses the insert mode, the operation would be also affected by the current indentation mode. (Though one can try to work that around with :set paste/:set nopaste.)
I would have tried to put the text into a temp variable or register then Pput (or :put) it into the buffer. E.g. setreg() allows one to tell that the content of a register are lines and thus Putting it would work regardless of indentation.
Otherwise, looking in :help line-continuation or :help variables I see no way how one can specify a multi-line string or text.

Resources