How to figure out key map redefined in vim plugin? - vim

I installed many plugins by vundle.
I found there maybe multiple plugins use the same hotkey.
Is there smart way to figure out which plugin contains such hotkey?
There are some tutorial about key map. But I still haven't any idea.

A warning
Don't just install many plugins; you'll end up with a complex, slow, and indecipherable mess over time. Especially with plugin managers like Vundle, it's very easy to check out plugins. That benefit can turn bad if you forget to remove plugins that don't turn out to be useful for you.
How to check
In general, the plugin should advertise its features and defaults mappings (and hopefully provides configuration to change those!)
If you indeed have overlapping mappings, you should check:
The plugin's documentation.
The plugin's source code; look for :*[nore]map commands in the plugin/pluginname.vim script.
The actual existing mappings; the :map command lists those. You can restrict the command by modes (e.g. :imap for insert mode mappings) and starting keys (e.g. :map <Leader> lists all mappings that begin with the (configurable) Leader key).
How to change mappings
The canonical way to change plugin mappings is by defining your own mapping to <Plug>... targets that the plugin provides, e.g. :nmap <F1> <Plug>PluginNameMapping, in your ~/.vimrc. Some plugins also use global variables; refrain from modifying the plugin script itself; rather, complain to its author!

Yes, there is.
Use :verbose map <YOURKEY>. It will show you which file was the latest to modify this mapping.

You can always try reading the plugins documentation or source... Till then:
:map <YOURKEY><CR>
will show what was <YOURKEY> mapped to (in normal mode, so you can try it with :cmap, :vmap, etc.). Sometimes it helps if it's mapped to a function which relates to the plugins' name.
And you can issue a single (c|v...) :map to dump the mapping table.
But assuming you might want to know about mapping which used in two (or more plugins), there is no easy way for that. Again, look at the plugins' documentation and/or source code.

Related

Unmap <leader> hotkeys in VIM

I would like to use longer leader hotkeys to group or associate several common things that I do.
For instance <leader>dnd would do something, and <leader>dnt would do something related but different.
However, if <leader>d or <leader>dn is aready taken by a plugin, a longer leader hotkey is impossible.
Is there a way to unmap leader commands from plugins?
You can always :unmap any mapping after a plugin file has been sourced. This would typically be done in ~/after/plugin/fixmapping.vim for global mappings. But this is clumsy, and nothing more than a workaround.
If the plugins are (dare I say, correctly (1)) written with leaving the final choice to the end-user in mind, they would permit to bind any hot-key sequence of your choice to <Plug>(something) -- and then they would detect there is already something bound to <Plug>(something) and they would not associate <leader>whatever to <plug>(something).
You'll have to dig into the documentation of the plugin with a default configuration you don't like to see first if it permits to override defaults, and then how it can be done. If the plugin doesn't permit it, I'd recommend you open a request for enhancement/change.
(1) Sometimes we just publish a quickly written solution/proof of concept. The first drafts are not ideally designed/written. Yet they can evolve to be more professional. Do not be afraid to contact plugin maintainers.

Vim not recognizing some commands from vim-latex

I have vim-latex installed via Vundle and I'm trying to disable some annoying mapping that it sets up by default. From the docs I know that, for example, I can use the following command to unmap FEM:
call IUNMAP('FEM','tex')
But when I type that I get the error E117: Unknown function: IUNMAP.
I have installed vim-latex with Vundle by including Plugin 'LaTeX-Suite-aka-Vim-LaTeX' in my vimrc and I have just used the PluginUpdate command to update everything, which runs with no error, so I should have the latest version of the package.
Am I missing something here?
Actually, the problem you're having is related to where you're getting your vim-latex from.
With:
Plug 'LaTeX-Suite-aka-Vim-LaTeX'
You're getting it from here, which you'll notice hasn't been updated since 2010. Looking at the plugin/imaps.vim file in that repository, you'll see there's a definition for function IMAP(), but not for IUNMAP(), which was probably introduced after the last date that repository was synced...
Use this source instead:
Plug 'vim-latex/vim-latex'
Which will get it from here which is an official maintained location for this plug-in.
If you look at plugin/imaps.vim in that source tree, you'll notice function! IUNMAP is defined there.
Updating to the correct plug-in location should fix this problem for you (together with probably quite a few fixes from the last 10 years!)
The functions IMAP() and IUNMAP() are loaded by the vim-latex plug-in only after your vimrc is processed. So you need to execute them from a context where they're available.
Furthermore, in order to have your unmapping succeed, you need to actually execute it after the mapping was created, and mappings are typically created when the filetype is set.
The documentation mentions that these overriding rules should be done in specific files:
An important thing to note is that if you wish to over-ride macros created by Latex-Suite rather than merely create new macros, you should place the IMAP() (or IUNMAP()) calls in a script which gets sourced after the files in Latex-Suite.
A good place typically is as a file-type plugin file in the ~/.vim/after/ftplugin/ directory. [...]
For example, to delete a mapping, you can use
call IUNMAP('FEM', 'tex')
in ~/.vim/after/ftplugin/tex_macros.vim.
The documentation mentions that you should use a file in ftplugin after the filetype you use. Check :set ft? to confirm yours is indeed tex, in which case you can use tex.vim, tex_something.vim (like the suggested tex_macros.vim) or tex/something.vim (a subdirectory.)

How does <Plug> work in Vim?

I didn't understand what <Plug> does and how to use it. I read the documentation but it is not clear to me.
<Plug> is just a special, synthetic key that is never actually sent by the keyboard; i.e. you cannot type it.
With this, the :map functionality that comes from old vi can be used as an abstraction layer for plugins.
Instead of directly mapping plugin functionality to a fixed key, plugins define a <Plug>PluginNameFunctionName mapping, which can then be freely remapped to the desired key by the user. As Vim allows to check for existing mappings (via hasmapto()), plugins can also define a default mapping if none was specified by the user.
TL;DR
for your own personal mappings, you can ignore <Plug>
if you use a plugin and need to customize its mappings, :map your own left-hand side to the <Plug>-mapping(s) provided by the plugin
if you write a plugin, enable user customization as described in :help using-<Plug>

How to manage the vim Mappings

How to manage Vim Mappings, since each plugins (Pathogen is a great tool used to manage to manage Vim plugins) come with its own mappings. Collisions occur regularly.
Each plugin should come with a description (ideally accessible via the built-in :help) that includes the commands and mappings it defines. You need to read that anyway, in order to find out about the new functionality. You should also remember if one of the plugin's mappings clashes with an existing mapping of yours. :verbose map ... is a simple and great way to investigate your existing mappings.
In case of clashes, plugins using :map <unique> will fail noticeably, but most plugins will just silently overwrite a taken mapping. To fix that, a plugin should define <Plug>... mappings (see :help using-<Plug>; if it doesn't, complain to the author), which allow you to redefine the mappings (according to your tastes or to avoid a clash) in your ~/.vimrc. For example:
:nmap <C-o> <Plug>EnhancedJumpsOlder
The same can also be used to disable a mapping altogether:
:nmap <Plug>DisableEnhancedJumpsNewer <Plug>EnhancedJumpsNewer
Unless you have a lot of custom mappings (e.g. to emulate a different editor's feel in Vim, which you shouldn't do), or you're using lots of plugins, clashes should not be that frequent.

Refactoring in Vim

Of course the fact that you can refactor on IDEs is priceless for many, I hardly ever do it when I am coding but I may try to do it when editing some one else's source. How do you accomplish such a trivial task across multiple files in Vim?
I found this plugin for refactoring Ruby, but how about "any" language?
I agree with the 'Vim is not an IDE' paradigm. But there are times when there isn't an IDE. Here's what I use in those situations:
Disclaimer: The ubiquity of Language Server Protocol servers, linters and fixers since I wrote this have also brought some great refactoring capabilities to Vim (and other editors). IMO they are a long way from equaling the capabilities of a purpose-built IDE (I prefer ALE and nvim-lspconfig for these kinds of features). See other answers on this question for more info!
:grep, :vimgrep, :GrepperAg, :Ggrep
Refactoring that has more to do with regular replacements I usually use :grep on my project tree and then record a macro to do the refactor - :g and :s are no brainers. Usually it'll let me quickly modify a large number of files with very little effort. Honestly, I use this method more than any other.
Depending on your workflow the built-in commands might be slow/inconvenient. If you use git, then you'll wanna use the excellent Fugitive plugin and its :Ggrep command to only search files checked into git. I also like the vim-grepper because it is search-tool-agnostic (supports ag, sift, ripgrep, etc) and speedy.
:argdo, :cdo, and :bufdo
:cdo and :argdo are handy to execute vim commands over a set of files.
command line
When it's harder to determine the list of files that need changes via :vimgrep I resort to the command line grep/find commands to more closely curate the list of files that I need to refactor. Save the list to a text file and use :e and a mashup of macro recordings to make the changes I need to make.
I find that the less rusty I keep my macro recording skills the more useful I find Vim for refactoring: feeling comfortable saving/restoring from registers, incrementing/decrementing register counter variables, cleaning/saving macro recordings to file for later use, etc.
Update
Since writing this more videocasts for the methods I describe have been published on vimcasts.org (I encourage you to watch ALL the Vimcasts!). For refactoring watch these ones:
Substitution with :Subvert
Project wide search/replace
Search multiple files with :vimgrep
Use :argdo to change multiple files
Vimgolf is also a great way to practice.
Language Server Protocol (LSP)
The Language server protocol contains the feature for smart renaming of symbols across a project:
https://microsoft.github.io//language-server-protocol/specifications/specification-3-14/#textDocument_rename
For example following language server support this:
Clangd for C++
ccls for C/C++/Objective-C
Eclipse.jdt.ls for Java
pyls (with rope) for Python
tsserver for TypeScript
Solargraph for Ruby
gopls official lsp for Go (alpha stage in Nov 2019)
texlab for LaTeX
You can find more language servers under https://langserver.org/.
Vim
A vim editor client is necessary to use them within vim. Following options exist:
LanguageClient-neovim (requires rust) suggests the mapping:
nnoremap <silent> <F2> :call LanguageClient_textDocument_rename()<CR>
coc.nvim (requires node.js) suggests the mapping:
" Remap for rename current word
nmap <leader>rn <Plug>(coc-rename)
Ale has
nnoremap <silent> <Plug>(ale_rename) :ALERename<Return>
Ale does not define any keybindings. This has to be done by the user.
vim-lsp provides following command
:LspRename
Similar to Ale no mapping is suggested. However, of course you can define one as following
nmap <leader>r <plug>(lsp-rename)
(<leader>r is to be replaced by your choice; I do not know one which most plugins agree on)
vim-lsc has a default mapping:
'Rename': 'gR'
See also YouCompleteMe which facilitates LSPs as well.
Neovim
Neovim has initial builtin support for lsp since 13.11.2019
See for common configurations of LSPs the project nvim-lspconfig which suggests <space>rn as a mapping for vim.lsp.buf.rename().
Other Refactorings
I do not know if there are plans for the LSP protocol to support more complex refactorings, such as changing class structure, adding parameters to methods/functions or moving a method to a different class. For a list of refactorings see https://refactoring.com/catalog/.
Python
For the python language following plugins provide 'smart' renaming capabilities for vim:
jedi-vim (github) <leader>r
ropevim (github) CTRL-c r r
python-mode (github) :h pymode-rope-refactoring
C-Family
Try the plugin Clighter for rename-refactoring for the c-family. It is based on clang, but there are limitations and the plugin is marked as deprecated.
Suggested mapping by Clighter is
nmap <silent> <Leader>r :call clighter#Rename()<CR>
Note, the successor plugin clighter8 has removed the renaming functionality in the commit 24927db42.
If you use neovim, you can take a look at the plugin clamp. It suggests
nmap <silent> <Leader>r :call ClampRename()<CR>
Maybe not the most elegant solution, but I found it very handy: I use ECLIM to connect VIM and Eclipse. Of course all my source code editing is done in VIM, but when it's time to refactor, one can take advantage of Eclipse's superior cababilities in this matter.
Give it a try.
I wrote this plugin for generic refactoring. It still requires many improvements. Sometime in the future I'll try to abandon ctags in favour of clang for C&C++ refactorings.
Plugin YouCompleteMe (YCM) (20k stars on github)
http://ycm-core.github.io/YouCompleteMe/#the-refactorrename-new-name-subcommand
:h RefactorRename-new-name
In supported file types, this command attempts to perform a semantic
rename of the identifier under the cursor. This includes renaming
declarations, definitions and usages of the identifier, or any other
language-appropriate action. The specific behavior is defined by the
semantic engine in use.
Similar to FixIt, this command applies automatic modifications to your
source files. Rename operations may involve changes to multiple files,
which may or may not be open in Vim buffers at the time. YouCompleteMe
handles all of this for you. The behavior is described in the
following section.
Supported in filetypes: c, cpp, objc, objcpp, cuda, java, javascript,
typescript, rust, cs
By default there is no mapping.
Plugin Factorus
There is another vim plugin dedicated for refactoring called factorus which is available on github.
Currently (2017-12), it supports the languages
c,
java, and
python.
Place cursor at name to refactor and type
gd (or gD if you're refactoring a global variable).
Then
cgn new_name esc
and
. one or more times to refactor next occurrence(s)
or
:%norm . to refactor all occurrences in the buffer at once.
I write a lot of C/C++ code in vim. The most common refactoring that I do is renaming variables, class names, etc. Usually, I use :bufdo :%s/source/dest/g to do a search/replace in files, which is almost the same as renaming provided by big IDE's.
However, in my case, I found that I usually rename similar entities, spelled in different cases (i.e CamelCase, snake_case, etc.), so I decided to write a small utility to help with this kind of "smart-case" search/replace, it is hosted here. It is a command-line utility, not a plugin for vim, I hope that you can find it useful.
Go
The tool godoctor (github) supports several refactoring capabilities
Rename
Extract Function
Extract Local Variable
Toggle var ⇔ :=
Add Godoc stubs
There is a vim plugin https://github.com/godoctor/godoctor.vim which makes them available
With cursor in thing to rename:
:Rename <newname>
Highlighting block to extract:
:Refactor extract newfunc
vim-go
Precise type-safe renaming of identifiers with :GoRename.
Language server gopls
https://github.com/golang/tools/blob/master/gopls/doc/status.md#rename
For refactoring, if you're using Unite (and you should), you can then use vim-qfreplace and make it extremely easy. Check this video that demonstrates how it works. Once your workflow is set, you can make some mappings to optimize it (instead of typing most things like in the video).
A combination of two plugins: vim-ripgrep, to find across files and put the results in the quickfix window, and quickfix-reflector to save the changes right in the quickfix window and have it automatically save each change across the files.
I would consider using the spacemacs version of emacs. It is uses the same modes and most keystrokes as Vim but has many more add-on because of it's lisp nature. If you want to program in C++ you just add the c++ layer and most of the IDE is just set up for you already. For other interpreted languages like python or bash you do not need to leave spacemacs to use them. They even have a way to run blocks of code directly within your text which works fantastic for literate programming or reproducible programming where the code and the data are in the same file. Both done as text.
Spacemacs is much more heavy handed in it's initial load but the additional stuff you can do with it is worth the few seconds of startup cost. One layer org-mode is worth checking it out. It is the best outliner, programmer, day timer / todo list I have ever used.
The CoC addon has (among other features) the ability to rename variables.
https://github.com/neoclide/coc.nvim
" Symbol renaming.
nmap <leader>rn <Plug>(coc-rename)

Resources