I'd like to define a text object for tab-delimited fields in a tsv file. So far, I have
vnoremap af :<C-U>silent! normal! T<Tab>vf<Tab><CR> omap af :normal Vat<CR> vnoremap if :<C-U>silent! normal! T<Tab>vt<Tab><CR> omap if :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
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 if :<C-U>call TsvField(1)<CR> omap if :normal vit<CR> vnoremap af :<C-U>call TsvField(0)<CR> omap af :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 fixes this particular case – while breaking all the others. It seems
[^[:blank:]] might be the answer.