`imap` conditional to white space left of cursor - vim

Is it possible to have the following command be in effect
imap <Tab> <C-N>
unless the character left of the cursor is a white space, in which case, <Tab> should be <Tab>
(or as an interesting variant, unless the text left of the cursor matches ^\s*$, where $ stands for the end of the string left of the cursor) ?
Edit : solution
Thanks to the link provided by #Meninx
I found the following snippet in the vim Help
function! CleverTab()
if strpart( getline('.'), 0, col('.')-1 ) =~ '^\s*$'
return "\<Tab>"
else
return "\<C-N>"
endif
endfunction
inoremap <Tab> <C-R>=CleverTab()<CR>
which precisely implements what I wanted.

You do not need the <C-R>= in the inoremap. It is wiser to use an <expr> argument to inoremap, it will evaluate the last argument as an expression and then substitute the result. In your example it would look as follows:
function! CleverTab()
if strpart( getline('.'), 0, col('.')-1 ) =~ '^\s*$'
return "\<Tab>"
else
return "\<c-x>\<c-p>"
endif
endfunction
inoremap <expr> <tab> CleverTab()
Most inoremap maps are performed with <expr>, otherwise things become too complex too quickly.
Note that I also changed <C-N> to <c-x><c-p>. In most cases a context sensitive completion will find a better match looking backward than forward, since you are using it to repeat some text.
Also, we have a Vim specific part of the website: https://vi.stackexchange.com/

Related

How to make f and t wrap around the current line in vim

Is there a way to make the 'f' and 't' command wrap around the line? For example, if I have
Hello, my name is _intz,
where _ denotes my cursor position, I would like to be able to press fl for vim to place my cursor on the first l on the line.
Similarly, I would ideally like the , and ; commands to also wrap on the current line.
Thank you
No, this is not possible without implementing the feature yourself.
Note that fF are universally expected to mean "next on the line" and tT to mean "previous on the line", both of which being extremely useful in their own right. Instead of changing their meaning, and thus reducing the overall usefulness of Vim, you should consider making new commands.
Something like these quick and dirty mappings:
" move the cursor on first occurrence of character on the line
nnoremap <expr> <key> '0f' . nr2char(getchar())
" move the cursor before first occurrence of character on the line
nnoremap <expr> <key> '0t' . nr2char(getchar())
See :help <expr>, :help nr2char(), :help getchar().
With the help of this answer https://vi.stackexchange.com/questions/29167/determine-if-there-is-a-matching-character-on-the-current-line-past-the-cursor, the following maps <c-f> to allow that gives it the functionality of f with same line wrapping.
function!Neweff()
let character = nr2char(getchar())
let beforejump = getpos('.')
execute 'norm! f'.character.''
let afterjump = getpos('.')
if beforejump == afterjump
let firstcharacter = getline(".")[0]
execute 'norm! 0'
if character !=# firstcharacter
execute 'norm! f'.character.''
endif
endif
endfunction
nnoremap <c-f> :call Neweff()<CR>

Setting to skip over punctuation when moving forwards and backwards words

When I'm using vim I generally never want to move to a punctuation mark when I press w or b to go forwards or backwards. So I'm wondering if there's a setting or something to change this functionality?
e.g. If I've got some code like
object.method(args)
and my cursor is at the [o] in "object" then I want w to move to the [m] in "method", and another w to move to the [a] in "args". I don't want it to land on the [.] or the [(]. If I've ever wanted to move to a punctuation char I've always used f or F to jump straight to it. I've never personally wanted to move to a punctuation char when I move through words and I just realized this is really bugging me.
I too find that I would like a movement that is more inclusive that w, but not as inclusive as W. In particular, I would like a movement that only considers tokens beginning with alphanumeric characters as significant.
So I came up with the following:
" <SPACE> : forward to next word beginning with alphanumeric char
" <S-SPACE> : backward to prev word beginning with alphanumeric char
" <C-SPACE> : same as above (as <S-SPACE> not available in console Vim
" <BS> : back to prev word ending with alphanumeric char
function! <SID>GotoPattern(pattern, dir) range
let g:_saved_search_reg = #/
let l:flags = "We"
if a:dir == "b"
let l:flags .= "b"
endif
for i in range(v:count1)
call search(a:pattern, l:flags)
endfor
let #/ = g:_saved_search_reg
endfunction
nnoremap <silent> <SPACE> :<C-U>call <SID>GotoPattern('\(^\\|\<\)[A-Za-z0-9_]', 'f')<CR>
vnoremap <silent> <SPACE> :<C-U>let g:_saved_search_reg=#/<CR>gv/\(^\\|\<\)[A-Za-z0-9_]<CR>:<C-U>let #/=g:_saved_search_reg<CR>gv
nnoremap <silent> <S-SPACE> :<C-U>call <SID>GotoPattern('\(^\\|\<\)[A-Za-z0-9_]', 'b')<CR>
vnoremap <silent> <S-SPACE> :<C-U>let g:_saved_search_reg=#/<CR>gv?\(^\\|\<\)[A-Za-z0-9_]<CR>:<C-U>let #/=g:_saved_search_reg<CR>gv
nnoremap <silent> <BS> :call <SID>GotoPattern('[A-Za-z0-9_]\(\>\\|$\)', 'b')<CR>
vnoremap <silent> <BS> :<C-U>let g:_saved_search_reg=#/<CR>gv?[A-Za-z0-9_]\(\>\\|$\)<CR>:<C-U>let #/=g:_saved_search_reg<CR>gv
" Redundant mapping of <C-SPACE> to <S-SPACE> so that
" above mappings are available in console Vim.
"noremap <C-#> <C-B>
if has("gui_running")
map <silent> <C-Space> <S-SPACE>
else
if has("unix")
map <Nul> <S-SPACE>
else
map <C-#> <S-SPACE>
endif
endif
I have had this for a long time now, and I find that I use <SPACE>/<C-SPACE> movements so much more than w and W; it just seems more useful when coding. You can, of course, map the commands to whatever keys you find useful or more appropriate.
Even running the risk of creating a script for something that's built-in (like
I did last time), here is a little function that may help accomplishing
this.
function! JumpToNextWord()
normal w
while strpart(getline('.'), col('.')-1, 1) !~ '\w'
normal w
endwhile
endfunction
Basically, what it does is executing the standard w and repeating it
if the character under the cursor is not in a word character (feel free to
change that pattern.
If you add that and a little map in your .vimrc:
nnoremap <silent> ,w :call JumpToNextWord()<CR>
It should work.

vim function for toggling colorschemes

At the moment I'm using two different keys to toogle the colorscheme
map <F8> :colors wombat256 <cr>
map <F9> :colors dimtag <cr>
I want to achieve a toggle behavior like this
function! ToggleDimTags()
if (g:colors_name == "wombat256")
colors dimtag
else
colors wombat256
endif
endfunction
My problem is that ToogleDimTags() is resetting the cursor position to the first line on every call, which is undesirable. Any suggestions appreciated.
As discussed in the comments, the problem is that your map calling :execute
behaves a little differently, what you probably want is :call instead:
nnoremap <F5> :call ToggleDimTags()
To clarify what #ZyX was saying, :h :exec contains the following text:
:exe :execute
:exe[cute] {expr1} .. Executes the string that results from the evaluation
of {expr1} as an Ex command.
[...]
So what :execute really does is evaluating the expression looking for a string
that will be executed as an Ex command (also called colon commands). In other words:
exec ToggleDimTags() | " <-- ToggleDimTags() is evaluated and returns 0
exec 0
Which is:
:0
Now, :h :call:
:cal :call E107 E117
:[range]cal[l] {name}([arguments])
Call a function. The name of the function and its arguments
are as specified with |:function|. Up to 20 arguments can be
used. **The returned value is discarded**.
[...]
Update
I've been thinking about your function, and using the ternary operator and a bit
of :execute magic, you can simplify it up to a point where you discard the extra
function:
nnoremap <silent> <F9> :exec "color " .
\ ((g:colors_name == "wombat256") ? "dimtag" : "wombat256")<CR>
Here, this nnoremap will not produce output (<silent>) and is based on
:exec, which is followed by this expression:
"color " . ((g:colors_name == "wombat256") ? "dimtag" : "wombat256")
When g:colors_name is set to wombat256, the expression evaluates to:
"color dimtag"
Or, otherwise:
"color wombat256"
Then either one is evaluated by :exec. Of course you can join the lines
(without forgetting to remove the backslash), I did it like this simply to avoid
a too long line.

Make Vim Curly Braces, Square Braces, Parens act like Textmate

So I guess I'm not searching for the right thing but I'm looking to see how you can get VIM to act like Textmate when it comes to writing a set of curly braces, parens, or square brackets hit enter and you get this. Pipe indicates cursor.
function doSomething(){
|
}
#selector{
|
}
Instead of this garbage
function doSomething(){
|}
#selector{
|}
I already have the [{( closing each other when they are typed just the return and indentation is jacked. As usual any help would be appreciated.
I use the following mappings in my .vimrc:
inoremap {<cr> {<cr>}<c-o>O<tab>
inoremap [<cr> [<cr>]<c-o>O<tab>
inoremap (<cr> (<cr>)<c-o>O<tab>
So when I input:
function foo(){<cr>
I get:
function foo(){
|
}
Similar with (<cr> and [<cr>.
A note to delimitMate users
When using the delimitMate plugin, the mappings of the other answers interfere with the plugin. Luckily, this behavior is already available in delimitMate (but disabled by default), by setting the delmitMateExpansion options. E.g. add
let delimitMate_expand_cr = 1
to your .vimrc
This is my modification of Randy Moris' answer that works better for me:
inoremap {<cr> {<cr>}<c-o><s-o>
inoremap [<cr> [<cr>]<c-o><s-o>
inoremap (<cr> (<cr>)<c-o><s-o>
My solution for this was to put this little function (with corresponding insert-mode mapping) in my .vimrc:
fun! MyCR()
if strpart(getline('.'), col('.') - 2, 2) == '{}'
return "\<CR>\<CR>\<Up>\<Tab>"
endif
return "\<CR>"
endfun
autocmd FileType c,cpp inoremap <CR> <C-R>=MyCR()<CR>
You can change the autocmd so that it will work for your preferred file types.
It remaps <CR> in insert mode to check if the cursor is currently inside curly braces and adds the extra line and indentation where appropriate.
If you like Text make you should check Vim plugin, snipMate, as indicated by tarek11011.
For C/C++ it has by default a snippet for functions
# Function
snippet fun
${1:void} ${2:function_name}(${3}) {
${4:/* code */}
}
, which would solve the curly braces issue.
I have the following on my .vimrc
imap {<Space> {<Space><Space>}<left><left>
imap { {<CR>}
imap {<CR> {<CR><CR>}<Up>;<Esc>==i
imap ( ()
imap () ()
inoremap <silent> (. ().<C-x><C-o>
inoremap <silent> (- ()-><C-x><C-o>
imap (<space> (<space><space>)<left><left>
imap [ []
imap [<space> [<space><space>]<left><left>
inoremap " ""<left>
inoremap "" ""
ok, explanations:
when you hit {, sometimes you want to break a line and put and ending }, but sometimes you just want to stay in the same line, just like: a = {1,2,3};
# means where the cursor is:
So when you hit { and just after that you hit space -> { # }
when you hit { after a little delay or any other than space is used the line will be break
when you hit { just after an enter, the code will be:
foo(){
#
}
When you hit (. results in ().<call to omnicomplete> Just line namespace::Singleton::Create().
You have to use inoremap with ", to avoid infinite """""""""""""""""""""""
I have set ai in my vimrc which I believe does what you want?

Auto insert text at a newline in vim

I am editing a LaTeX file with vim. When I am in the \begin{itemize} environment, is there any way to tell vim to autoinsert \item whenever I open a new line?
function CR()
if searchpair('\\begin{itemize}', '', '\\end{itemize}', '')
return "\r\\item"
endif
return "\r"
endfunction
inoremap <expr><buffer> <CR> CR()
Put this into your .vim/ftplugins/tex.vim file (or any .vim inside .vim/ftplugins/tex directory).
I would recommend http://vim-latex.sourceforge.net. This package defines several maps useful for latex.
In particular for inserting \item you press <ATL-I>
I know noting about latex but I think it is a good idea to search in vim scripts
use the search button up left :D
for example search for
latex auto completion
I can hit Cntl-I and it'll put it in for me in either normal mode or insert mode. This is what I put in my .vimrc:
:imap <C-i> \item
:nmap <C-i> o\item
Note that there is a space at the end of \item.
I hacked the script ZyX supplied and came up with this. It adds support for the o and O commands. It does not require LaTeX-VIM.
function AddItem()
if searchpair('\\begin{itemize}', '', '\\end{itemize}', '')
return "\\item "
else
return ""
endif
endfunction
inoremap <expr><buffer> <CR> "\r".AddItem()
nnoremap <expr><buffer> o "o".AddItem()
nnoremap <expr><buffer> O "O".AddItem()
Extended Version of Answer by Samad Lotia and ZyX
Place this in your ~/.vim/after/ftplugin/tex.vim
function! AddItem()
let [end_lnum, end_col] = searchpairpos('\\begin{', '', '\\end{', 'nW')
if match(getline(end_lnum), '\(itemize\|enumerate\|description\)') != -1
return "\\item "
else
return ""
endif
endfunction
inoremap <expr><buffer> <CR> getline('.') =~ '\item $'
\ ? '<c-w><c-w>'
\ : (col(".") < col("$") ? '<CR>' : '<CR>'.AddItem() )
nnoremap <expr><buffer> o "o".AddItem()
nnoremap <expr><buffer> O "O".AddItem()
Improvements
auto-insert of \item also happens for environments enumerate and description
auto-insert of \item only happens if the immediate surrounding environment is one of the three (itemize/enumerate/description). It does not happen in following circumstance
\begin{itemize}
\item
\begin{minipage}
<CURSOR>
\end{minipage}
\end{itemize}
auto-insert of \item only happens if you are at the end of the line
deletion of auto inserted \item by pressing <CR> a second time. If one wants to add some indention in this case, change '<c-w><c-w>' to '<c-w><c-w><c-t>'.

Resources