Vim per file mappings - vim

I tried to put the following in my file header:
#!/bin/sh
# vim:set ts=2 sts=2 sw=2 expandtab:
# vim:map <leader>t :w\|:!./script.sh <cr>:
But Vim always complains about the map, saying that it's invalid. I also tried nnoremap with no success. What should I do to fix this (I want it in this file only)?

Modelines are only for options.
If you want this mapping only for that file, add this snippet to your ~/.vimrc:
augroup ThisFile
autocmd!
autocmd BufRead,BufNew /path/to/file nnoremap <buffer> <leader>t :w\|:!./script.sh <cr>:
augroup END
edit
It looks like you want a mapping for executing the current file. If so, you are really chasing the wrong rabbit, here, and also crashing real hard in the XY Problem wall.
You can use % as a synonym for "the file associated with the current buffer" so, assuming your script is executable, this command would execute it:
:w|!./%<CR>
Therefore, you could simply put this generic mapping in your ~/.vimrc:
nnoremap <leader>t :w\|!./%<CR>
Note 1: See :help c_% for the meaning of % and in that context.
Note 2: The bar needs to be escaped when used in a mapping, see :help map_bar.

Related

Vimrc autocmd runs command instead of mapping

I want to add a hotkey to my vim to run my python files, so I have added the following line to my vimrc:
autocmd FileType python map <F5> :w|!python3 %
But on opening the file instead of running autocmd, it runs python with my file.
For me this seems no different from what many tutorials suggest on using autocmd and map, so I'd like to know what exactly is happening here instead of the behavior I expect.
Your :map command ends at the command separator |; the remainder is already executed when the :autocmd runs. You need to escape it (\|), or better use the special <Bar> character:
autocmd FileType python nnoremap <buffer> <F5> :w<Bar>!python3 %<CR>
Cp. :help map_bar. Also, you should use :noremap; it makes the mapping immune to remapping and recursion. And (as #PeterRincker suggested), make the mapping buffer-local, so that it only applies to Python buffers).
Your :autocmd FileType approach is fine for a few mappings, but it doesn't scale well. If you have :filetype plugin on in your ~/.vimrc, you can factor our your mappings into a separate script ~/.vim/ftplugin/python_mappings.vim.

Run selected text through filter and reinsert

I like using code cleanup scripts; perldidy; uglifierjs, etc. I previously ran them all like this in my vimrc...
map <leader>pt :!perltidy<CR>
map <leader>jt :!uglifyjs -b<CR>
map <leader>pjt :!python -mjson.tool<CR>
map <leader>ct :!column -t<CR>
How this functionally works; it runs currently selected text throguh the CLI program, and replaces the selection with the output. Works wonderfully; but as you can see I now have to stop and think what beautifier I want to run and remember the nemonic I have for it. This led me to think there has to be a better way. So I tried did this...
map <leader>jt :call RunTidy()<cr>
function! RunTidy()
if (&ft == "javascript")
echo 'is js..'
:'<,'>!ulifyjs -b
endif
if (&ft == "json")
echo 'is json'
:'<,'>!python -mjson.tool
endif
endfunction
The problem being this just doesn't work; executing once for each line and not replacing contents.. Anyone aware of a better way to do this? I feel like this should be a solved problem...
augroup filters
autocmd!
autocmd FileType perl map <buffer> <leader>t :!perltidy<CR>
autocmd FileType javascript map <buffer> <leader>t :!uglifyjs -b<CR>
autocmd FileType json map <buffer> <leader>t :!python -mjson.tool<CR>
augroup END
or put those mappings, all with the same lhs, in different ~/.vim/after/ftplugin/{filetype}.vim.
Use ftplugins. You need to have filetype plugin indent on in your vimrc.
Create files in ~/.vim/ftplugin/<filetype>.vim. These files will be sourced when the file type is set.
For example using javascript put the following in ~/.vim/ftplugin/javascript.vim
noremap <buffer> <leader>jt :!uglifyjs -b<CR>
to map <leader>jt to :!uglifyjs -b<CR> in all javascript buffers. This will not show up in other filetypes.
You would do the same for all other filetypes.
You can do the same for file type specific settings by using setlocal.
Take a look at :h ftplugin

vim conditional keymap when a tex file is open

I am trying to make a keymap that will call latexmk when .tex is available (it would be better if .tex is the currently open and active buffer)
I tried :
:nnoremap <Leader>lw :if filereadable('*.tex')<cr>up!<cr>:!latexmk -pdf<cr>endif<cr>
when trying to make latexmk -pdf run, but unfortunately, its just prompting those line in the window, and doing nothing like:
~
:if filereadable('*.tex')
: up!
: :call Tex_RunLaTeX()
: endif
Press ENTER or type command to continue
kindly help.
(it will be great, as told, if this can be done when .tex is the currently open and active buffer.)
NB: this question and its variant has been asked here several time here eg this and this, hence sorry for the repetation. I have failed to solve my problem with those.
You need to do 3 things:
fix your mapping to run the command properly
create a mapping local to a specific buffer by using the <buffer> option for nnoremap.
load the mappings for just a specific filetype.
First fix the mapping by using executing the command as single ex command by using <bar> and removing :'s & <cr>'s. We also remove the filereadable portion because we just wrote the file.
nnoremap <buffer> :up!<bar>!latexmk -pdf<cr>
or you can use an expressing mapping like FDinoff suggested.
Note the <buffer> option on the mapping. This makes the mapping only available to the current buffer not every buffer.
Now we need to make sure this mapping only works for tex filetypes. This can be done via an autocommand in your .vimrc like so:
autocmd FileType tex nnoremap <buffer> :up!<bar>!latexmk -pdf<cr>
The other way option is by creating a filetype plugin. (see :h ftplugin for more details)
A simple example is do create a file named, ~/.vim/ftplugin/text.vim and place your mappings inside like so:
nnoremap <buffer> :up!<bar>!latexmk -pdf<cr>
I personally lean more towards the ftplugin approach but having a everything in your .vimrc file can be nice.
I feel like this could be done with an autocmd.
The autocmd only loads the mapping when the file is a tex file.
autocmd FileType tex nnoremap <leader>lw :up! \| !latexmk -pdf<CR>
If you want to do this filereadable('*.tex') which just checks to see if a file in the directory is a tex file. You could use the expr mapping from the first link. In the else part of the expression we just put an empty string so the mapping will do nothing.
nnoremap <expr> <leader>lw filereadable('*.txt') ? ':up! \| !latexmk -pdf<CR>' : ''

Can you have file type-specific key bindings in Vim?

In my .vimrc file, I have a key binding for commenting out that inserts double slashes (//) at the start of a line:
" the mappings below are for commenting blocks of text
:map <C-G> :s/^/\/\//<Esc><Esc>
:map <C-T> :s/\/\/// <Esc><Esc>
However, when I’m editing Python scripts, I want to change that to a # sign for comments
I have a Python.vim file in my .vim/ftdetect folder that also has settings for tab widths, etc.
What is the code to override the keybindings if possible, so that I have Python use:
" the mappings below are for commenting blocks of text
:map <C-G> :s/^/#/<Esc><Esc>
:map <C-T> :s/#/ <Esc><Esc>
You can use :map <buffer> ... to make a local mapping just for the active buffer. This requires that your Vim was compiled with +localmap.
So you can do something like
autocmd FileType python map <buffer> <C-G> ...
The ftdetect folder is for scripts of filetype detection. Filetype plugins must be inside the ftplugin folder. The filetype must be included in the file name in one of the following three forms:
.../ftplugin/<filetype>.vim
.../ftplugin/<filetype>_foo.vim
.../ftplugin/<filetype>/foo.vim
For instance, you can map comments for the cpp filetype putting the following inside the .../ftplugin/cpp_mine.vim:
:map <buffer> <C-G> :s/^/\/\//<Esc><Esc>
:map <buffer> <C-T> :s/\/\/// <Esc><Esc>
I prefer to have my configuration in a single file so I use the autocmd approach.
augroup pscbindings
autocmd! pscbindings
autocmd Filetype purescript nmap <buffer> <silent> K :Ptype<CR>
autocmd Filetype purescript nmap <buffer> <silent> <leader>pr :Prebuild!<CR>
augroup end
Vim doesn't clear set autocmds when you source your vimrc, so starting vim, changing something in your vimrc and running :so ~/.vimrc would define autocmds twice. That's why the bindings are grouped and cleared with autocmd! group_name. You can read more here.
Since mappings are applied to every buffer by default, and you want to change them for buffers matching the filetype only, the <buffer> modifier is in there, limiting the mappings to the local buffer.
Btw... if your primary problem is about commenting... you should check out 'nerdcommenter' plugin, its the fastest way to comment/uncomment your code in java/c/c++/python/dos_batch_file/etc etc.
This is only a partial answer for people coming here having difficulties getting any ftplugin scripts working, but remember that your .vimrc (or a file that it sources) should contain
filetype plugin on
or
:filetype plugin on
for filetype-plugins to be executed when a file of a given type is loaded.
I recommend the .../ftplugin/<filetype>.vim approach that freitass suggests, but in your specific case Vim Commentary will solve all of this for you.

Vim: <leader> key sequences are interfused with normal mode mappings

I'm trying to define mappings for "cpp" filetype:
autocmd! FileType cpp map <leader>c echo "test c"
autocmd! FileType cpp map <leader>r echo "test r"
autocmd! FileType cpp map <leader>t echo "test t"
My leader key is redefined:
let mapleader = ","
When I open *.cpp file only one of the mappings works as expected: the ",t" sequence makes the "echo" happen, but the other two behaves as if there were no any mappings defined: ",r" makes Vim to switch to replace mode and ",c" brings Vim to insert mode.
What am I doing wrong?
I don't know how your example (including ,c one) could work: you forgot to prepend echo with a colon. But there is another mistake: according to the help:
:au[tocmd]! [group] {event} {pat} [nested] {cmd}
Remove all autocommands associated with {event} and {pat}, and add the command {cmd}.
So, the last one (,t) should replace all previous ones.
There are also another things you should to consider:
Don't use map, use noremap instead: it may once save you from doing a debug job after you add some mapping.
If you define filetype mapping you should normally add <buffer> as an argument to :noremap in a position before {lhs}: it will make this mapping local to the current buffer.
In case you want to re-source vimrc you should put all command into augroup:
augroup VimrcCpp
autocmd!
autocmd FileType cpp nnoremap <buffer> <leader>c :echo "c"<CR>
autocmd FileType cpp nnoremap <buffer> <leader>r :echo "r"<CR>
autocmd FileType cpp nnoremap <buffer> <leader>t :echo "t"<CR>
augroup END
I would have removed it from vimrc and added to ~/.vim/ftplugin/cpp.vim (after directory is to be used only to override options that you don't like if they are unconditionally defined by a plugin. If there are no mapping conflicts, don't use after).
I suggest you put those mapping in a file called cpp.vim placed in your ~/.vim/after/ftplugin/ (or any equivalent based on OS) directory.
Vim automatically loads it as long as you have
filetype plugin on
in your .vimrc.
This saves you writing autocommands and keeps your configuration well organized.

Resources