Wikia

Vim Tips Wiki

Changes: Insert a single character

Edit

Back to page

(Change <tt> to <code>, perhaps also minor tweak.)
(Comments: yet another solution)
 
(8 intermediate revisions by 4 users not shown)
Line 1: Line 1:
{{review}}
 
 
{{TipImported
 
{{TipImported
 
|id=270
 
|id=270
Line 12: Line 11:
 
|category2=
 
|category2=
 
}}
 
}}
Using insert mode to insert a single character feels clumsy (you need three keypresses for one character), so here's a slightly easier way:
+
Using insert mode to insert a single character feels clumsy because three key presses are needed to insert one character. Here is a slightly easier way:
 
<pre>
 
<pre>
:nmap <Space> i_<Esc>r
+
:nnoremap <Space> i_<Esc>r
 
</pre>
 
</pre>
   
Now, when in normal mode, just press space followed by what it is you want to insert.
+
Now, when in normal mode, press Space followed by the character that you want to insert.
   
Bug: Repeating the insertion with <code>.</code> doesn't work.
+
Bug: Repeating the insertion with <code>.</code> does not work.
   
 
==Comments==
 
==Comments==
I prefer <C-I> as a {lhs}. It <strike>is unused and</strike> fits better to the insert logic of Vim, although it saves fewer key strokes.
+
I use:
 
----
 
I use
 
 
<pre>
 
<pre>
:map gt i_<Esc>r
+
:nnoremap ,i i_<Esc>r
:map gb a_<Esc>r
+
:nnoremap ,a a_<Esc>r
 
</pre>
 
</pre>
 
----
 
The author was looking for a way to save a keystroke. Both solutions are 3 keystrokes long.
 
A solution that also moves the cursor to the right would be better.
 
   
 
----
 
----
Line 41: Line 36:
 
Such inserts can be repeated with '<code>.</code>' thus making this command worthy (it's not a big problem to make an additional keypress but imagine you need to manually put some spaces or other separators).
 
Such inserts can be repeated with '<code>.</code>' thus making this command worthy (it's not a big problem to make an additional keypress but imagine you need to manually put some spaces or other separators).
   
PS. 's' and 'S' were chosen because:
+
's' and 'S' were chosen because:
 
*They remind of 'single'.
 
*They remind of 'single'.
 
*If they are used occasionally, one can use synonyms 'cl' and 'cc' instead.
 
*If they are used occasionally, one can use synonyms 'cl' and 'cc' instead.
   
::What is the "\e" for?
+
:What is the "\e" for?
::The built-in <code>s</code> command is very useful, but that's a choice for the user. [[User:JohnBeckett|JohnBeckett]] 22:56, 15 June 2009 (UTC)
+
::It might be meant to represent <Escape> although in Vim 7.2 this method does not need to force an escape from insert mode.
  +
:The built-in <code>s</code> command is very useful, but that's a choice for the user. [[User:JohnBeckett|JohnBeckett]] 22:56, 15 June 2009 (UTC)
   
 
----
 
----
  +
I quite like the solution you proposed, but it does not allow for repetitions, I found myself wanting to do '<code>5s </code>'. I couldn't use the repetition inline because it would repeat the call to getchar so I added a simple proxy function, the result is:
  +
<pre>
  +
function! RepeatChar(char, count)
  +
return repeat(a:char, a:count)
  +
endfunction
  +
nnoremap s :<C-U>exec "normal i".RepeatChar(nr2char(getchar()), v:count1)<CR>
  +
nnoremap S :<C-U>exec "normal a".RepeatChar(nr2char(getchar()), v:count1)<CR>
  +
</pre>
   
I quite like the solution you proposed, but it doesn't allow for repetitions, I found myself wanting to do '<code>5s </code>'. I couldn't use the repetition inline because it would repeat the call to getchar so I added a simple proxy function, the result is:
 
function! RepeatChar(char, count)
 
return repeat(a:char, a:count)
 
endfunction
 
nnoremap s :<C-U>exec "normal i".RepeatChar(nr2char(getchar()), v:count1)<CR>
 
nnoremap S :<C-U>exec "normal a".RepeatChar(nr2char(getchar()), v:count1)<CR>
 
 
Note that the C-U is necessary to support the ranges and as far as I could tell the '<code>."\e"</code>' was unnecessary, so I removed it
 
Note that the C-U is necessary to support the ranges and as far as I could tell the '<code>."\e"</code>' was unnecessary, so I removed it
 
:Interesting, thanks. Why wouldn't <code>repeat(getchar(), v:count1)</code> work (why the RepeatChar function)? [[User:JohnBeckett|JohnBeckett]] 11:20, September 28, 2010 (UTC)
 
:Interesting, thanks. Why wouldn't <code>repeat(getchar(), v:count1)</code> work (why the RepeatChar function)? [[User:JohnBeckett|JohnBeckett]] 11:20, September 28, 2010 (UTC)
 
::Because if you use repeat(nr2char(getchar()), v:count1) it executes the "nr2char(getchar())", "v:count1" times, meaning it will try to get "v:count1" keypresses. When you pass it as a parameter to a function it is evaluated only once and the result is repeated. 12:44, September 20, 2010 (UTC)
 
::Because if you use repeat(nr2char(getchar()), v:count1) it executes the "nr2char(getchar())", "v:count1" times, meaning it will try to get "v:count1" keypresses. When you pass it as a parameter to a function it is evaluated only once and the result is repeated. 12:44, September 20, 2010 (UTC)
  +
  +
----
  +
This is what I am using for a similar purpose. The only difference is, if a character is not provided promptly, it inserts a space:
  +
<pre>
  +
function! InsertSingle()
  +
sleep 120m|let l:a = getchar(0)
  +
if l:a != 0
  +
silent! exec "normal a" . nr2char(l:a)
  +
else
  +
silent! exec "normal a "
  +
endif
  +
endfunction
  +
nnoremap <silent> <Space> :call InsertSingle()<CR>
  +
</pre>
  +
  +
----
  +
By exploiting the InsertCharPre and InsertLeave events we could do the trick. Insertion of a specified number of characters or a single character can now be done without manually switching back to Normal mode.
  +
  +
Since I have switched to Neovim in which Meta key bindings works even in the terminal, I used <M-i> and <M-a> as the shortcuts. If you are using original Vim on a terminal, you could use the trick provided by Tim Pope in his rsi.vim plugin to make the meta key work.
  +
  +
<pre>
  +
let s:insert_char_pre = ''
  +
let s:insert_leave = ''
  +
  +
autocmd InsertCharPre * execute s:insert_char_pre
  +
autocmd InsertLeave * execute s:insert_leave
  +
  +
" basic layer
  +
function! s:QuickInput (operator, insert_char_pre)
  +
let s:insert_char_pre = a:insert_char_pre
  +
let s:insert_leave = 'call <SID>RemoveFootprint()'
  +
call feedkeys(a:operator, 'n')
  +
endfunction
  +
  +
function! s:RemoveFootprint()
  +
let s:insert_char_pre = ''
  +
let s:insert_leave = ''
  +
let s:char_count = 0
  +
endfunction
  +
  +
" secondary layer
  +
function! QuickInput_Count (operator, count)
  +
let insert_char_pre = 'call <SID>CountChars('.a:count.')'
  +
call <SID>QuickInput(a:operator, insert_char_pre)
  +
endfunction
  +
  +
let s:char_count = 0
  +
function! s:CountChars (count)
  +
let s:char_count += 1
  +
if s:char_count == a:count
  +
call feedkeys("\<Esc>")
  +
endif
  +
endfunction
  +
  +
" secondary layer
  +
function! QuickInput_Repeat (operator, count)
  +
let insert_char_pre = 'let v:char = repeat(v:char, '.a:count.') | call feedkeys("\<Esc>")'
  +
call <SID>QuickInput(a:operator, insert_char_pre)
  +
endfunction
  +
  +
nnoremap i :<C-u>execute 'call ' v:count? 'QuickInput_Count("i", v:count)' : "feedkeys('i', 'n')"<CR>
  +
nnoremap a :<C-u>execute 'call ' v:count? 'QuickInput_Count("a", v:count)' : "feedkeys('a', 'n')"<CR>
  +
  +
nnoremap <Plug>InsertAChar :<C-u>call QuickInput_Repeat('i', v:count1)<CR>
  +
nnoremap <Plug>AppendAChar :<C-u>call QuickInput_Repeat('a', v:count1)<CR>
  +
  +
nmap <M-i> <Plug>InsertAChar
  +
nmap <M-a> <Plug>AppendAChar
  +
</pre>
 
----
 
----

Latest revision as of 13:31, November 21, 2015

Tip 270 Printable Monobook Previous Next

created 2002 · complexity basic · author Mikko Pulkkinen · version 6.0


Using insert mode to insert a single character feels clumsy because three key presses are needed to insert one character. Here is a slightly easier way:

:nnoremap <Space> i_<Esc>r

Now, when in normal mode, press Space followed by the character that you want to insert.

Bug: Repeating the insertion with . does not work.

CommentsEdit

I use:

:nnoremap ,i i_<Esc>r
:nnoremap ,a a_<Esc>r

I consider this a better solution:

:nnoremap s :exec "normal i".nr2char(getchar())."\e"<CR>
:nnoremap S :exec "normal a".nr2char(getchar())."\e"<CR>

Such inserts can be repeated with '.' thus making this command worthy (it's not a big problem to make an additional keypress but imagine you need to manually put some spaces or other separators).

's' and 'S' were chosen because:

  • They remind of 'single'.
  • If they are used occasionally, one can use synonyms 'cl' and 'cc' instead.
What is the "\e" for?
It might be meant to represent <Escape> although in Vim 7.2 this method does not need to force an escape from insert mode.
The built-in s command is very useful, but that's a choice for the user. JohnBeckett 22:56, 15 June 2009 (UTC)

I quite like the solution you proposed, but it does not allow for repetitions, I found myself wanting to do '5s '. I couldn't use the repetition inline because it would repeat the call to getchar so I added a simple proxy function, the result is:

function! RepeatChar(char, count)
  return repeat(a:char, a:count)
endfunction
nnoremap s :<C-U>exec "normal i".RepeatChar(nr2char(getchar()), v:count1)<CR>
nnoremap S :<C-U>exec "normal a".RepeatChar(nr2char(getchar()), v:count1)<CR>

Note that the C-U is necessary to support the ranges and as far as I could tell the '."\e"' was unnecessary, so I removed it

Interesting, thanks. Why wouldn't repeat(getchar(), v:count1) work (why the RepeatChar function)? JohnBeckett 11:20, September 28, 2010 (UTC)
Because if you use repeat(nr2char(getchar()), v:count1) it executes the "nr2char(getchar())", "v:count1" times, meaning it will try to get "v:count1" keypresses. When you pass it as a parameter to a function it is evaluated only once and the result is repeated. 12:44, September 20, 2010 (UTC)

This is what I am using for a similar purpose. The only difference is, if a character is not provided promptly, it inserts a space:

function! InsertSingle()
  sleep 120m|let l:a = getchar(0)
  if l:a != 0
    silent! exec "normal a" . nr2char(l:a)
  else
    silent! exec "normal a "
  endif
endfunction
nnoremap <silent> <Space> :call InsertSingle()<CR>

By exploiting the InsertCharPre and InsertLeave events we could do the trick. Insertion of a specified number of characters or a single character can now be done without manually switching back to Normal mode.

Since I have switched to Neovim in which Meta key bindings works even in the terminal, I used <M-i> and <M-a> as the shortcuts. If you are using original Vim on a terminal, you could use the trick provided by Tim Pope in his rsi.vim plugin to make the meta key work.

let s:insert_char_pre = ''
let s:insert_leave = ''

autocmd InsertCharPre * execute s:insert_char_pre
autocmd InsertLeave   * execute s:insert_leave

" basic layer
function! s:QuickInput (operator, insert_char_pre) 
    let s:insert_char_pre = a:insert_char_pre
    let s:insert_leave = 'call <SID>RemoveFootprint()'
    call feedkeys(a:operator, 'n')
endfunction 

function! s:RemoveFootprint() 
    let s:insert_char_pre = ''
    let s:insert_leave = ''
    let s:char_count = 0
endfunction 

" secondary layer
function! QuickInput_Count (operator, count) 
    let insert_char_pre = 'call <SID>CountChars('.a:count.')'
    call <SID>QuickInput(a:operator, insert_char_pre)
endfunction 

let s:char_count = 0
function! s:CountChars (count) 
    let s:char_count += 1
    if s:char_count == a:count
        call feedkeys("\<Esc>")
    endif
endfunction 

" secondary layer
function! QuickInput_Repeat (operator, count) 
    let insert_char_pre = 'let v:char = repeat(v:char, '.a:count.') | call feedkeys("\<Esc>")'
    call <SID>QuickInput(a:operator, insert_char_pre)
endfunction 

nnoremap i :<C-u>execute 'call ' v:count? 'QuickInput_Count("i", v:count)' : "feedkeys('i', 'n')"<CR>
nnoremap a :<C-u>execute 'call ' v:count? 'QuickInput_Count("a", v:count)' : "feedkeys('a', 'n')"<CR>

nnoremap <Plug>InsertAChar :<C-u>call QuickInput_Repeat('i', v:count1)<CR>
nnoremap <Plug>AppendAChar :<C-u>call QuickInput_Repeat('a', v:count1)<CR>

nmap <M-i> <Plug>InsertAChar
nmap <M-a> <Plug>AppendAChar

Around Wikia's network

Random Wiki