Getting 'E488: Trailing characters' With the following function - vim

Does anyone know why I'm getting the following error? I'm mapping the following function
function! ToggleCompileErrors()
:if w:syntastic_is_open == 1
:call SyntasticReset()<CR>
let w:syntastic_is_open = 0
:else
:call SyntasticCheck()<CR>
let w:syntastic_is_open = 1
:endif
endfunction
With this command
command ToggleCompileErrors :call ToggleCompileErrors()
and it is getting called by the following keymapping
nnoremap <Leader>b :ToggleCompileErrors<CR>
And I don't know if it makes a difference but I am using neovim 0.2.2

Watch your modes. That <CR> :help key-notation is necessary for mappings, but not inside functions, which use Ex commands.
Likewise, you don't need to prefix commands inside a function with : (and this is rather odd here, especially because you're not even consistent about it). : is a normal mode command that enters command-line mode. As commands in a function already are Ex commands, the : is not needed.

Related

How to execute a command from cnoremap?

I want to map <M-o> to quickly look up buflist from command-mode.
Here's an example normal-mode mapping:
nnoremap <M-o> :ls<CR>
Here's an attempt to do the same for command mode using execute():
cnoremap <M-o> <C-r>=execute(':ls')<CR>
This however simply appends whitespace-separated :ls results to the command line, with no side effect of the :ls table actually showing.
Is there a way to execute a command without leaving command-mode?
Update:
Closest I've come to cracking this using Vimscript is the following:
function! RunCmdFromCmdline(cmd)
let l:cmd_line = getcmdline()
echo execute(a:cmd)
return l:cmd_line
endfunction
cnoremap <M-o> <C-\>eRunCmdFromCmdline(':ls')<CR>
The echo makes it so the results of a:cmd do pop on the screen, however in invisible font. I tried playing with :redraw <bar> in different combinations with no success.
Exiting from the command mode from within a <C-r>= or <C-\>e prompt does not seem possible.
You can save the contents of the current command line in a register, then run ls and paste the contents of the register:
cnoremap <esc>o <home>let #x="<end>"<cr>:ls<cr>:<c-r>x
So if command line looks like this:
:echo 'some'
type <M-o> to get:
:ls
1 %a + "filename" line 1
:echo 'some'
This works. It uses global variables, but arguably this is an acceptable use for them, since there's only a single command-line you can be in at a time.
function! SaveCmdline()
let g:save_cmdline = getcmdline()
let g:save_cmdpos = getcmdpos()
return ''
endfunction
function! RestoreCmdline()
call setcmdpos(g:save_cmdpos)
return g:save_cmdline
endfunction
cnoremap <M-o> <C-\>eSaveCmdline()<CR>ls<CR>:<C-\>eRestoreCmdline()<CR>
This works with whatever quotes or unfinished syntax you have in your command-line, restores the full command-line and the cursor to the position it was before running the command, doesn't mess with any registers (only touches the two global variables) and doesn't mess with command-line history either (see q: command for history.)
It does have one tiny bug, in that cnoremap actually also works when you're typing a search expression (after / or ?) among a few other sub-modes (see getcmdtype() for a list of those.) If you use the mapping there, it will search for "ls" and then restore your search term as an Ex command, oops...
You can probably use getcmdtype() to detect that and possibly only perform the actions while you're typing an Ex command and not in the other modes.
UPDATE: This fixes the last part, only executing the command while in the Ex command-line, not in search or other context. It also makes the interjected command parameterizable.
function! CmdlineExecute(cmd)
if getcmdtype() != ':'
return ''
endif
return "\<C-\>eSaveCmdline()\r".a:cmd.
\ "\r:\<C-\>eRestoreCmdline()\r"
endfunction
cnoremap <expr> <M-o> CmdlineExecute('ls')
(Note this still needs the definition of the two functions above.)

Hitting ENTER on quickfix error jumps to an empty buffer

I'm using GVim 8.1 on Windows 10 with no external plugins.
I have the following set up in my .gvimrc file:
let g:build_file_abs_path = fnamemodify(findfile("windows-build.bat", ";."), ":p:h")
" This build script is a basic wrapper for 'clang.exe file.c -o file.exe' style invocation
let &makeprg=g:build_file_abs_path . "\\windows-build.bat"
nnoremap <silent> <C-B> :cd <C-R>=g:build_file_abs_path<CR> <bar> make! <bar> copen <bar> redraw <bar> cd -<CR>
Now, this automatically opens a quickfix window with the correct compiler output. However, when I press ENTER over the error, the cursor jumps to the buffer for the affected file, yet it is completely blank with a single line. Furthermore, this occurs as I use :cn and :cp commands inside the quickfix window. e.g:
Images showing these two states:
before
after
Please note that:
:verbose nmap <CR> returns no mappings, so there is not conflict there.
I would appreciate it if someone could provide some insight as to how to avoid the buffer becoming empty and actually jump to the error in the appropriate file. Many thanks.
Thanks to Christian Brabandt's comment, I was able to solve the issue. I was misunderstanding the distinction between the working directories of vim and the build script. I made the following changes:
let &makeprg="cd " . g:build_file_abs_path . " && windows-build.bat"
nnoremap <silent> <C-B> :make! <bar> copen <bar> redraw <CR>

Calling hjkl keys from vim's command line

Whenever I am browsing folded code in vim and press the l key I want it to open that fold recursively. For that I did the following: nmap l lzO. Which worked ok, apart from the fact of getting a E490: No fold found whenever I would press l not in a fold. I used that an excuse to learn about Vimscript and write a function for that and avoid the error.
Now, I am missing the part of how can I call a vim command like l or lzO from inside a function?
function! OpenFoldOrNot()
if foldclosed(line(".")) == -1
echo "just l"
l # TODO
else
echo "open fold"
lzO # TODO
endif
endfunction
nmap l :call OpenFoldOrNot()<CR>
Try the normal command. For this case you will need normal! to avoid recursive execution of your function.
You could try the following, using the normal command (my vimscript is very rusty):
function! OpenFoldOrNot()
if foldclosed(line(".")) == -1
normal! l
else
normal! lzO
endif
endfunction
nmap l :call OpenFoldOrNot()<CR>
Alternatively you can use a map-expression to make this kind of job easier.
nnoremap <expr> l foldclosed(line(".")) == -1 ? 'l' : 'lzO'
In a map expression the right hand side, {rhs}, of the mapping is a VimScript expression. This is evaluated to obtain what to execute. In your case it is used to determine if the mapping calls l or lz0.
For more help see:
:h :map-expression

Vim - Pydoc plugin not working with operator mapping

I have a small operator mapping for use with the Pydoc plugin. The code for it is below:
nnoremap <buffer> <localleader>d :set operatorfunc=<SID>PydocOperator<cr>g#
vnoremap <buffer> <localleader>d :<c-u>call <SID>PydocOperator(visualmode())<cr>
function! s:PydocOperator(type)
let l:orig_register = ##
if a:type ==# 'v'
normal! `<v`>y
elseif a:type ==# 'char'
normal! `[v`]y
else
return
endif
execute 'Pydoc ' . shellescape(##)
let ## = l:orig_register
endfunction
However, vim throws an error:
E116: Invalid arguments for function <SNR>117_ShowPyDoc
The same error happens if I copy some text manually and run this command:
execute 'Pydoc ' . shellescape(##)
This is very odd, considering that the :Pydoc should work as a normal command, taking one argument as its input. I looked at the code where the :Pydoc command is defined, (that line of code is here) and discovered that passing an argument to the :Pydoc command that is in quotes might be causing an issue. So I ran :Pydoc 'sys' to see if it would throw the same error as the operator mapping, which it did. So if it is having an issue with the quotes around the argument, how do I format the execute command so that it doesn't give an invalid argument?
The shellescape() function is not necessary for the :Pydoc command. shellescape includes quotes in the returned string, which causes :Pydoc to self destruct. However, if the command were :grep, for instance, shellescape would need to be used.
Relevant help topics:
:help shellescape()
:help 'operatorfunc'
:help :map-operator

Unable to get this function working in .vimrc

Not sure if this is the best place for this question but following this http://vim.wikia.com/wiki/Using_the_Windows_clipboard_in_Cygwin_Vim article I put this function Putclip in my vimrc however it doesnt seem to get triggered.
vnoremap <silent> <leader>y :call Putclip(visualmode(), 1)<CR>
nnoremap <silent> <leader>y :call Putclip('n', 1)<CR>
I thought the above two calls to the function should work in vm mode or normal mode when pressing y command. Even the highlight on mouse in vm mode doesnt work. Can someone please let me know what im doing wrong.
I use cygwin as the environment to do this and using vim version 7.3.
These map the command not to y, but to <leader>y. By default, the leader key is a backslash, so the command is really bound to \y. You can change that by setting the mapleader variable to something else before mapping a command to a key sequence incorporating it:
let mapleader = ","
vnoremap <silent> <leader>y :call Putclip(visualmode(), 1)<CR>
Now the function would be bound to ,y instead of \y.

Resources