I'd like to define a text object for tab-delimited fields in a tsv file. So far, I have
vnoremap ataf :<C-U>silent! normal! T<Tab>vf<Tab><CR>
omap ataf :normal Vat<CR>
vnoremap itif :<C-U>silent! normal! T<Tab>vt<Tab><CR>
omap itif :normal Vit<CR>
The problem is with the first and the last field because those lack a tab on one side. I've experimented with ?[\t\n]?e+1
and search()
instead of T<Tab>
(and analogously for the ending), using various patterns for defining text objects that I've found online, but nothing seems to work.
EDIT: Eventually I came up with this, but I can't help the feeling it's an overkill. If someone comes up with a nicer solution, I'll be very happy to learn.
function! TsvField (inner)
" first field
if getline('.')[:col('.')-1] !~ "\t[^[:blank:]]"
execute a:inner ? "normal ^vt\t" : "normal ^vf\t"
" last field
elseif getline('.')[col('.')-1:] !~ "\t"
execute a:inner ? "normal T\tv$h" : "normal F\tv$h"
" middle field
else
execute a:inner ? "normal T\tvt\t" : "normal T\tvf\t"
endif
endfunction
vnoremap itif :<C-U>call TsvField(1)<CR>
omap itif :normal vit<CR>
vnoremap ataf :<C-U>call TsvField(0)<CR>
omap ataf :normal vat<CR>
EDIT 2: After some more testing I discovered that [^\s]
does not match the letter s
, so the first if
fails when one of the fields begins with this letter. Replacing [^\s]
with \S
fixes this particular case – while breaking all the others. It seems [^[:blank:]]
might be the answer.