Stanimirovv
Stanimirovv

Reputation: 3172

Vim (vimscript) get exact character under the cursor

I am getting the character under the cursor in vimscript the following way:

getline('.')[col('.')-1] 

It works exactly like it should, however there is something I dislike. consider this [] the cursor. When there is a bracket next to the cursor like so: }[] , ][] , )[] or {[] the cursor actually returns the bracket. What do I have to set so it will always return the character exactly under the cursor or atleast ignore if there is a bracket to it's left?

Note: I suspect that it might have to do with the brackets highlight, though I am not sure.

Note2: for the situation to occur there has to be a matching bracket.

Upvotes: 20

Views: 11057

Answers (4)

qeatzy
qeatzy

Reputation: 1551

Try this one, it works for both ascii and multi-byte characters.

echo strpart(getline('.'), col('.')-1, 1, 1)

Brief explanation: with strpart(s, idx, 1, 1) With the last 1, it says, given me 1 character (instead of 1 byte) starting at byte idx.

This is probably fastest version, no regex, no copy. (Vimscript string is not reference counted, thus slicing will create a copy.)

Upvotes: 0

jdhao
jdhao

Reputation: 28369

Another way to get the character index under cursor that deal with both ASCII and non-ASCII characters is the like the following:

function! CharAtIdx(str, idx) abort                                       
  " Get char at idx from str. Note that this is based on character index  
  " instead of the byte index.                                            
  return strcharpart(a:str, a:idx, 1)                                     
endfunction
                                                                          
function! CursorCharIdx() abort                                           
  " A more concise way to get character index under cursor.               
  let cursor_byte_idx = col('.')                                          
  if cursor_byte_idx == 1                        
    return 0                      
  endif                                                                   
                             
  let pre_cursor_text = getline('.')[:col('.')-2]                         
  return strchars(pre_cursor_text)                                        
endfunction                                                               

Then if you want to get char under cursor, use the following command:

let cur_char_idx = CursorCharIdx()
let cur_char = CharAtIdx(getline('.'), cur_char_idx)

See also this post on how to get pre-cursor char.

Upvotes: 0

Ace
Ace

Reputation: 181

nr2char(strgetchar(getline('.')[col('.') - 1:], 0))

or

strcharpart(getline('.')[col('.') - 1:], 0, 1)

Upvotes: 6

Ingo Karkat
Ingo Karkat

Reputation: 172590

Though I cannot reproduce the problem you're describing, there's another problem with your code: Because of the string indexing (and this is one of the uglier sides of Vimscript), it only works with single-byte characters, but will fail to capture chars like Ä or 𠔻 (depending on the encoding used). This is a better way of capturing the character under the cursor:

:echo matchstr(getline('.'), '\%' . col('.') . 'c.')

Edit: Since about Vim 7.4.1742, Vim has new strgetchar() and strcharpart() functions that work with character indexes, not byte addressing. This is helpful in many circumstances, but not here, because you still can only get the byte-index position of the cursor (or the screen column with virtcol(), but that's not the same as character index).

Upvotes: 35

Related Questions