Monday, January 31, 2011

Re: properly yanking word/selection

Reply to message «properly yanking word/selection»,
sent 19:25:55 31 January 2011, Monday
by sgp:

> 1/ yaw (yank a word) yanks the space before the word (some times it
> doesn't); I don't want the space.
Possible suggestions here:
1. use «let @"=expand("<cword>")» (@" is a register variable, expand("<cword>")
will expand to the word under the cursor (mnemonic: *c*urrent *word*)).
2. Use «normal! yiw», it won't take a space.
3. Do «let @"=substitute(@", '^\s\+', '', '')» thus removing preceding spaces.

> 2/ bSelection is needed to tell a function that it was invoked from visual
> mode; is there a better way?
If you want to use «normal!», then no. You may use «mode()» function for <expr>
mappings, but mapping expressions are executed inside a textlock with additional
restrictions including inability to use normal. Changing registers is still
allowed, but yanking a selection without «normal!» requires much more work, for
example see my getvrange function:

"{{{3 map.getvrange
function s:F.map.getvrange(start, end)
let [sline, scol]=a:start
let [eline, ecol]=a:end
let text=[]
let ellcol=col([eline, '$'])
let slinestr=getline(sline)
if sline==eline
if ecol>=ellcol
call extend(text, [slinestr[(scol-1):], ""])
else
call add(text, slinestr[(scol-1):(ecol-1)])
endif
else
call add(text, slinestr[(scol-1):])
let elinestr=getline(eline)
if (eline-sline)>1
call extend(text, getline(sline+1, eline-1))
endif
if ecol<ellcol
call add(text, elinestr[:(ecol-1)])
else
call extend(text, [elinestr, ""])
endif
endif
return text
endfunction

It does not put anything into a register (because it was written in order to
obtain text in a given range without modifying selection, marks and registers).
It is able to obtain only characterwise range, for linewise range it will much
simpler, for blockwise range it is more complex if you want to handle
virtualedit (otherwise it is simpler). Note that I do not know a way to set a
register that includes NULL, though vim somehow preserves NULLs when using yank
commands. This function also preserves NULLs: it returns a list of strings where
NL in each string really means NULL (it is a common format for
readfile/writefile and getline/setline/append functions). Note that ecol must
point to last byte of last character, if it points to first byte (it will when
you use getpos), use

let lchar=len(matchstr(getline(eline), '\%'.ecol.'c.'))
if lchar>1
let ecol+=lchar-1
endif

This function maybe does not worth time spent on it, but it was a good trial.

Original message:
> What is the proper way to yank a word or a selection from a vim script?
> Right now I'm using if !bSelection
> normal! yaw
> else
> normal! gvy
> endif
>
> but I have some gripes:
>
> 1/ yaw (yank a word) yanks the space before the word (some times it
> doesn't); I don't want the space. 2/ bSelection is needed to tell a
> function that it was invoked from visual mode; is there a better way?
>
> TIA

No comments: