Skip to content

Commit 7afd63b

Browse files
committed
label-mode: support multibyte labels
Useful especially with 'keymap'. fix #246
1 parent 24e6c3f commit 7afd63b

File tree

3 files changed

+86
-56
lines changed

3 files changed

+86
-56
lines changed

autoload/sneak/label.vim

Lines changed: 20 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,16 @@ let s:matchmap = {}
1212
let s:match_ids = []
1313
let s:orig_conceal_matches = []
1414

15+
if exists('*strcharpart')
16+
func! s:strchar(s, i) abort
17+
return strcharpart(a:s, a:i, 1)
18+
endf
19+
else
20+
func! s:strchar(s, i) abort
21+
return matchstr(a:s, '.\{'.a:i.'\}\zs.')
22+
endf
23+
endif
24+
1525
func! s:placematch(c, pos) abort
1626
let s:matchmap[a:c] = a:pos
1727
let pat = '\%'.a:pos[0].'l\%'.a:pos[1].'c.'
@@ -76,8 +86,7 @@ func! s:do_label(s, v, reverse, label) abort "{{{
7686
endif
7787

7888
if i < s:maxmarks
79-
"TODO: multibyte-aware substring: matchstr('asdfäöü', '.\{4\}\zs.') https://github.com/Lokaltog/vim-easymotion/issues/16#issuecomment-34595066
80-
let c = strpart(g:sneak#target_labels, i, 1)
89+
let c = s:strchar(g:sneak#target_labels, i)
8190
call s:placematch(c, p)
8291
else "we have exhausted the target labels; grab the first non-labeled match.
8392
let overflow = p
@@ -107,7 +116,7 @@ func! s:do_label(s, v, reverse, label) abort "{{{
107116
call feedkeys(choice) "exit label-mode and fall through to Vim.
108117
return ""
109118
else "valid target was selected
110-
let p = mappedtoNext ? s:matchmap[strpart(g:sneak#target_labels, 0, 1)] : s:matchmap[choice]
119+
let p = mappedtoNext ? s:matchmap[s:strchar(g:sneak#target_labels, 0)] : s:matchmap[choice]
111120
call cursor(p[0], p[1])
112121
endif
113122

@@ -202,23 +211,24 @@ func! s:is_special_key(key) abort
202211
\ || (g:sneak#opt.s_next && maparg(a:key, 'n') =~# '<Plug>Sneak\(_s\|Forward\)')
203212
endf
204213

205-
"we must do this because:
206-
" - we don't know which keys the user assigned to Sneak_;/Sneak_,
207-
" - we need to reserve special keys like <Esc> and <Tab>
214+
" We must do this because:
215+
" - Don't know which keys the user assigned to Sneak_;/Sneak_,
216+
" - Must reserve special keys like <Esc> and <Tab>
208217
func! sneak#label#sanitize_target_labels() abort
209-
let nrkeys = sneak#util#strlen(g:sneak#target_labels)
218+
let nrbytes = len(g:sneak#target_labels)
210219
let i = 0
211-
while i < nrkeys
220+
while i < nrbytes
221+
" Intentionally using byte-index for use with substitute().
212222
let k = strpart(g:sneak#target_labels, i, 1)
213223
if s:is_special_key(k) "remove the char
214224
let g:sneak#target_labels = substitute(g:sneak#target_labels, '\%'.(i+1).'c.', '', '')
215-
"move ; (or s if 'clever-s' is enabled) to the front.
225+
" Move ; (or s if 'clever-s' is enabled) to the front.
216226
if !g:sneak#opt.absolute_dir
217227
\ && ((!g:sneak#opt.s_next && maparg(k, 'n') =~# '<Plug>Sneak\(_;\|Next\)')
218228
\ || (maparg(k, 'n') =~# '<Plug>Sneak\(_s\|Forward\)'))
219229
let g:sneak#target_labels = k . g:sneak#target_labels
220230
else
221-
let nrkeys -= 1
231+
let nrbytes -= 1
222232
continue
223233
endif
224234
endif

doc/sneak.txt

Lines changed: 36 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -148,9 +148,10 @@ NORMAL-MODE
148148
(previous) match. Additional matches are highlighted until the cursor is
149149
moved. Works across multiple lines.
150150

151-
If a |language-mapping| is activated, Sneak waits for keymapped sequences as
152-
needed and searches for the keymapped result as expected. (Requires Vim 7.3+)
153-
'keymap' 'iminsert' |mbyte-keymap|
151+
If a |language-mapping| ('keymap') is active Sneak waits for keymapped
152+
sequences as needed and searches for the keymapped result as expected. You
153+
probably want to set |g:sneak#target_labels| to labels that make sense for
154+
your preferred 'keymap'.
154155

155156
[count]s enters |sneak-vertical-scope| mode.
156157

@@ -263,66 +264,65 @@ g:sneak#t_reset = 1
263264

264265
Note: Defaults to 0 if you mapped f (or t) to any |sneak-mappings|.
265266

266-
0 : Pressing |f| (or |t|) will NOT clear the last Sneak search. So you could
267-
define different maps for <Plug>Sneak_; or <Plug>Sneak_, and still
268-
use ; and , for |f| and |t| as usual.
267+
0: Pressing |f| (or |t|) will NOT clear the last Sneak search. So you could
268+
define different maps for <Plug>Sneak_; or <Plug>Sneak_, and still
269+
use ; and , for |f| and |t| as usual.
269270

270-
1 : Pressing |f| (or |t|) causes Sneak to "reset" so that |;| and |,| will apply
271-
to the last f (or t) motion instead of the last s or S. This makes it
272-
possible to use ; and , for all three motions (f, t, and s).
271+
1: Pressing |f| (or |t|) causes Sneak to "reset" so that |;| and |,| will apply
272+
to the last f (or t) motion instead of the last s or S. This makes it
273+
possible to use ; and , for all three motions (f, t, and s).
273274

274-
Note: if f (or t) was already mapped by you or a plugin, Sneak will
275-
not override the existing mapping unless you explicitly set f_reset
276-
(or t_reset). This means Sneak will not be able to reset ; or , when
277-
you invoke f or t. See the README.md FAQ regarding "f-enhancement"
278-
plugins.
275+
Note: if f (or t) was already mapped by you or a plugin, Sneak will
276+
not override the existing mapping unless you explicitly set f_reset
277+
(or t_reset). This means Sneak will not be able to reset ; or , when
278+
you invoke f or t. See the README.md FAQ regarding "f-enhancement"
279+
plugins.
279280

280281
g:sneak#s_next = 0
281282

282-
0 : Disable |sneak-clever-s|.
283+
0: Disable |sneak-clever-s|.
283284

284-
1 : Enable |sneak-clever-s|. It works like this: immediately after
285-
invoking Sneak, press "s" _again_ to go to the next match, or "S" for
286-
the previous match. This behavior persists until you move the cursor.
287-
Note: You can still use |;| and |,| as usual.
285+
1: Enable |sneak-clever-s|. It works like this: immediately after
286+
invoking Sneak, press "s" _again_ to go to the next match, or "S" for
287+
the previous match. This behavior persists until you move the cursor.
288+
Note: You can still use |;| and |,| as usual.
288289

289290
g:sneak#absolute_dir = 0
290291

291-
0 : Relative direction. |;| goes to the next match in the direction of the
292-
initial s/S invocation and |,| goes in the opposite direction.
292+
0: Relative direction. |;| goes to the next match in the direction of the
293+
initial s/S invocation and |,| goes in the opposite direction.
293294

294-
1 : Absolute direction. Repeat via |;| or |,| always goes forwards or
295-
backwards respectively.
296-
Note: With |sneak-clever-s|, s and S behave the same as |;| and |,|.
295+
1: Absolute direction. Repeat via |;| or |,| always goes forwards or
296+
backwards respectively.
297+
Note: With |sneak-clever-s|, s and S behave the same as |;| and |,|.
297298

298299
g:sneak#use_ic_scs = 0
299300

300-
0 : Always case-sensitive
301+
0: Always case-sensitive
301302

302-
1 : Case sensitivity is determined by 'ignorecase' and 'smartcase'.
303+
1: Case sensitivity is determined by 'ignorecase' and 'smartcase'.
303304

304305
g:sneak#map_netrw = 1
305306

306-
0 : Don't do any special handling of "file manager" buffers (such as
307-
|netrw| or filebeagle).
307+
0: Don't do any special handling of "file manager" buffers (such as
308+
|netrw| or filebeagle).
308309

309-
1 : Set up Sneak mappings (s and S) in "file manager" buffers (|:Ex|,
310-
|:Vex|, filebeagle) and replace the default buffer-local s and
311-
S mappings with <leader>s and <leader>S.
310+
1: Set up Sneak mappings (s and S) in "file manager" buffers (|:Ex|,
311+
|:Vex|, filebeagle) and replace the default buffer-local s and
312+
S mappings with <leader>s and <leader>S.
312313

313314
g:sneak#label = 0
314315

315-
0 : Disable |sneak-label-mode|.
316+
0: Disable |sneak-label-mode|.
316317

317-
1 : Enable |sneak-label-mode| if the Vim |+conceal| feature is available.
318+
1: Enable |sneak-label-mode| if the Vim |+conceal| feature is available.
318319

319-
*g:sneak#label_esc*
320-
g:sneak#label_esc = "\<Space>"
320+
g:sneak#label_esc = "\<Space>" *g:sneak#label_esc*
321321

322322
Exit |sneak-label-mode| as if <Esc> were pressed.
323323
https://github.com/justinmk/vim-sneak/issues/122
324324

325-
g:sneak#target_labels = ";sftunq/SFGHLTUNRMQZ?0"
325+
g:sneak#target_labels = ";sftunq/SFGHLTUNRMQZ?0" *g:sneak#target_labels*
326326

327327
List of characters used to label the target locations. |sneak-label-mode|
328328

tests/test.vader

Lines changed: 30 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -899,9 +899,9 @@ Expect:
899899
foo æfïïooæ ïoòôõïo ïïofoo fïxïooïo
900900

901901
###########################################################
902-
# test language keymap
902+
# 'keymap'
903903

904-
Execute (activate language keymap):
904+
Execute (SETUP):
905905
set keymap=bulgarian-phonetic
906906

907907
Given:
@@ -918,17 +918,37 @@ Expect:
918918
абцдё еёееёП ЯВЕРПО
919919
абцдёё еёееёП ЯВЕРПО
920920

921-
Do (repeat search for multi-keymap):
921+
Do:
922922
se::e::;x
923-
Expect:
923+
Expect (repeat search for multi-keymap):
924924
abcdef abcdef abcdef
925925
абцдеф АБЦДЕФ абцдеф
926926
абцдёё еёееёП ЯВЕРПО
927927
абцдё еёееёП ЯВЕРПО
928928

929-
Execute (deactivate language keymap):
929+
Execute (SETUP):
930+
let g:sneak#target_labels = 'адсфгхйкл;'
931+
let g:sneak#label = 1
932+
call sneak#init()
933+
call sneak#label#sanitize_target_labels()
934+
Assert ';адсфгхйкл' ==# g:sneak#target_labels
935+
Given:
936+
яверуипоо пасдфкййл;
937+
яверуипоо пасдфкййл;
938+
яверуипоо пасдфкййл;
939+
яверуипоо пасдфкййл;
940+
яверуипоо пасдфкййл;
941+
Do:
942+
dzсдд
943+
Expect (keymap + label-mode + multibyte labels):
944+
сдфкййл;
945+
яверуипоо пасдфкййл;
946+
947+
Execute (TEARDOWN):
930948
set iminsert=0
931949
set keymap=
950+
let g:sneak#label = 0
951+
call sneak#init()
932952

933953
###########################################################
934954
# Sneak_f and Sneak_t
@@ -1023,16 +1043,16 @@ Expect:
10231043
ab7cdef ab8cdef ab9cdef ab0cdef ab1cdef ab2cdef
10241044
ab1cdef ab2cdef ab3cdef ab4cdef ab5cdef ab6cdef
10251045

1026-
Do (FIXME inclusive f-delete forward):
1046+
Do:
10271047
dvfe
1028-
Expect:
1048+
Expect (FIXME inclusive f-delete forward):
10291049
ef ab2cdef ab3cdef ab4cdef ab5cdef ab6cdef
10301050
ab7cdef ab8cdef ab9cdef ab0cdef ab1cdef ab2cdef
10311051
ab1cdef ab2cdef ab3cdef ab4cdef ab5cdef ab6cdef
10321052

1033-
Do (FIXME inclusive t-delete forward):
1053+
Do:
10341054
dvte
1035-
Expect:
1055+
Expect (FIXME inclusive t-delete forward):
10361056
def ab2cdef ab3cdef ab4cdef ab5cdef ab6cdef
10371057
ab7cdef ab8cdef ab9cdef ab0cdef ab1cdef ab2cdef
10381058
ab1cdef ab2cdef ab3cdef ab4cdef ab5cdef ab6cdef
@@ -1090,7 +1110,7 @@ Given:
10901110
abcdef abcdef abcdef
10911111

10921112
# issue #35
1093-
Do (sneak 'f', then Vim default 't', then sneak 'f'):
1113+
Do (sneak f, then Vim default t, then sneak f):
10941114
fderxtcrx
10951115
:\<C-U>doautocmd CursorMoved\<CR>
10961116
:\<C-U>doautocmd CursorMoved\<CR>

0 commit comments

Comments
 (0)