Reputation: 794
Here is what I do
:syntax match conceal Test +[A-Z0-9]\{6}+
:set conceallevel=2
:set concealcursor=nvi
So when I write 123456
in vim I expect it to be nothing there. But what actually happens when I move over that area is that I have to move 6 times in the direction I want to move for the cursor to pass that area.
Is there a way to work around this? I want vim to see it as if there is nothing there and that when I move over that area it's like there is nothing there. But I still want to be able to search for it and delete it.
Upvotes: 5
Views: 1287
Reputation: 695
ZyX's solution from above did not work for me: apparently the ID of a concealed text region can change while traversing it, causing the motion to stop prematurely.
I have been using an alternate version pasted below (also with the missing BackwardSkipConceal
function). It's not pretty but works well when substituting mathematical characters in LaTeX documents or C++ code.
function! ForwardSkipConceal(count)
let cnt=a:count
let mvcnt=0
let c=col('.')
let l=line('.')
let lc=col('$')
let line=getline('.')
while cnt
if c>=lc
let mvcnt+=cnt
break
endif
if stridx(&concealcursor, 'n')==-1
let isconcealed=0
else
let [isconcealed, cchar, group] = synconcealed(l, c)
endif
if isconcealed
let cnt-=strchars(cchar)
let oldc=c
let c+=1
while c < lc
let [isconcealed2, cchar2, group2] = synconcealed(l, c)
if !isconcealed2 || cchar2 != cchar
break
endif
let c+= 1
endwhile
let mvcnt+=strchars(line[oldc-1:c-2])
else
let cnt-=1
let mvcnt+=1
let c+=len(matchstr(line[c-1:], '.'))
endif
endwhile
return ":\<C-u>\e".mvcnt.'l'
endfunction
function! BackwardSkipConceal(count)
let cnt=a:count
let mvcnt=0
let c=col('.')
let l=line('.')
let lc=0
let line=getline('.')
while cnt
if c<=1
let mvcnt+=cnt
break
endif
if stridx(&concealcursor, 'n')==-1 || c == 0
let isconcealed=0
else
let [isconcealed, cchar, group]=synconcealed(l, c-1)
endif
if isconcealed
let cnt-=strchars(cchar)
let oldc=c
let c-=1
while c>1
let [isconcealed2, cchar2, group2] = synconcealed(l, c-1)
if !isconcealed2 || cchar2 != cchar
break
endif
let c-=1
endwhile
let c = max([c, 1])
let mvcnt+=strchars(line[c-1:oldc-2])
else
let cnt-=1
let mvcnt+=1
let c-=len(matchstr(line[:c-2], '.$'))
endif
endwhile
return ":\<C-u>\e".mvcnt.'h'
endfunction
nnoremap <expr> l ForwardSkipConceal(v:count1)
nnoremap <expr> h BackwardSkipConceal(v:count1)
Upvotes: 5
Reputation: 53654
Currently there is no built-in way to do this. You can use synconcealed()
to determine whether there is a concealed character under the cursor and what it is concealed to and remap all moving keys to respect it: like this:
function! ForwardSkipConceal(count)
let cnt=a:count
let mvcnt=0
let c=col('.')
let l=line('.')
let lc=col('$')
let line=getline('.')
while cnt
if c>=lc
let mvcnt+=cnt
break
endif
if stridx(&concealcursor, 'n')==-1
let isconcealed=0
else
let [isconcealed, cchar, group]=synconcealed(l, c)
endif
if isconcealed
let cnt-=strchars(cchar)
let oldc=c
let c+=1
while c<lc && synconcealed(l, c)[2]==group | let c+=1 | endwhile
let mvcnt+=strchars(line[oldc-1:c-2])
else
let cnt-=1
let mvcnt+=1
let c+=len(matchstr(line[c-1:], '.'))
endif
endwhile
return ":\<C-u>\e".mvcnt.'l'
endfunction
nnoremap <expr> l ForwardSkipConceal(v:count1)
. Note: this does the thing for one single motion (l
) and in normal mode, just to show the way it may be done.
Upvotes: 10