Hi Bram! On Di, 09 Jun 2015, Bram Moolenaar wrote:
> Christian Brabandt wrote: > > > > > Bram, > > > > There are still two open issues with langmaps. One is issue 297 > > > > (https://code.google.com/p/vim/issues/detail?id=297), the other one is > > > > this one > > > > (https://groups.google.com/d/msg/vim_dev/5D1WSL2gj-A/OgCBNZQEHNEJ) > > > > > > > > I have checked the problem and I think the problem is, that mappings > > > > won't be resolved after a multibyte characters have been read. This is > > > > caused, by the fact that vgetorpeek() that resolves mappings, doesn't > > > > know about multibyte chars, since those are only known in the higher > > > > level vgetc() function. But after applying the langmap there, Vim > > > > won't check, if the input needs to be resolved for mappings. > > > > > > > > Therefore I changed vgetc() function to resolve langmaps after the > > > > multibyte chars have been read correctly and once this changed the > > > > input character and a mapping for that character exists, put that > > > > character again into the typeahead buffer and run vgetorpeek() again. > > > > > > > > Attached patch includes 2 tests, that are taken from the above issues > > > > and demonstrate the problem. > > > > > > I think this is not right. LANGMAP_ADJUST() is already called inside > > > vgetorpeek(). After your change it would also be called on the result. > > > > Isn't that, what is happening currently anyhow? LANGMAP_ADJUST() is > > called inside vgetorpeek() and again in normal.c after safe_vgetc() > > Hmm, it's slightly differently. Inside vgetorpeek() LANGMAP_ADJUST() is > only used to check for a matching mapping. It's not used to actually > change the returned character. The LANGMAP_ADJUST() in normal.c does > the actual translation. > > So the problem in vgetorpeek() is that LANGMAP_ADJUST() is only applied > to a byte, not a character. Your change to call LANGMAP_ADJUST() in > vgetc() does cause a double translation. That can be avoided by > returning the original character, but it doesn't handle multi-character > mappings. > > I don't think there is a simple solution, would need to apply > LANGMAP_ADJUST() in vgetorpeek() on every character before checking for > a mapping, but not actually returning the adjusted character when no > mapping matches. It's tricky, as one can't call vgetorpeek() recursively to receive the next characters. Here is a patch, that seems to work and that does not seem to brake the other tests. So that is good. However, I don't know, from where to get characters from. I am not sure, if one needs to check the stuffbuf or other buffers to check for another char. Currently, this gets characters from the user and from the scriptfile (that I discovered from the non-working test ;)) I would appreciate some feedback especially if I need to get characters from other places as well or if there needs to be checked some more. Best, Christian -- Die Zukunft der Sprache ist die Formel. -- C. W. Ceram (eig. Kurt W Marek) -- -- You received this message from the "vim_dev" maillist. Do not top-post! Type your reply below the text you are replying to. For more information, visit http://www.vim.org/maillist.php --- You received this message because you are subscribed to the Google Groups "vim_dev" group. To unsubscribe from this group and stop receiving emails from it, send an email to vim_dev+unsubscr...@googlegroups.com. For more options, visit https://groups.google.com/d/optout.
diff --git a/src/getchar.c b/src/getchar.c --- a/src/getchar.c +++ b/src/getchar.c @@ -1998,6 +1998,7 @@ vgetorpeek(advance) #endif int old_wcol, old_wrow; int wait_tb_len; + int keylen_mb_off = 0; /* keylen adjustment for multibyte chars */ /* * This function doesn't work very well when called recursively. This may @@ -2141,14 +2142,52 @@ vgetorpeek(advance) ) { #ifdef FEAT_LANGMAP + int k = 1; + if (c1 == K_SPECIAL) nolmaplen = 2; else { +#ifdef FEAT_MBYTE + char_u buf[MB_MAXBYTES + 1]; + int j; + + if (has_mbyte && (k = MB_BYTE2LEN_CHECK(c1)) > 1) + { + if (typebuf.tb_len == 1) + { + /* get some more chars */ + j = inchar(typebuf.tb_buf + typebuf.tb_off + typebuf.tb_len, + typebuf.tb_buflen - typebuf.tb_off - typebuf.tb_len - 1, + 0, typebuf.tb_change_cnt); + typebuf.tb_len += j; + } + + if (typebuf.tb_len > 1) + { + buf[0] = c1; + for (j=1; j < k; ++j) + buf[j] = typebuf.tb_buf[typebuf.tb_off + j]; + } + /* need to remember, that we have to remove more bytes */ + keylen_mb_off = k - 1; + k = c1; + c1 = (*mb_ptr2char)(buf); + } +#endif LANGMAP_ADJUST(c1, (State & INSERT) == 0); + if (c1 == k) + keylen_mb_off = 0; nolmaplen = 0; } #endif +#ifdef FEAT_LANGMAP + if (MAP_HASH(local_State, c1) > 255) + { + c1 = k; + keylen_mb_off = 0; + } +#endif #ifdef FEAT_LOCALMAP /* First try buffer-local mappings. */ mp = curbuf->b_maphash[MAP_HASH(local_State, c1)]; @@ -2192,7 +2231,7 @@ vgetorpeek(advance) int c2; #endif /* find the match length of this mapping */ - for (mlen = 1; mlen < typebuf.tb_len; ++mlen) + for (mlen = 1 + keylen_mb_off; mlen < typebuf.tb_len; ++mlen) { #ifdef FEAT_LANGMAP c2 = typebuf.tb_buf[typebuf.tb_off + mlen]; @@ -2202,7 +2241,7 @@ vgetorpeek(advance) nomap = 2; else LANGMAP_ADJUST(c2, TRUE); - if (mp->m_keys[mlen] != c2) + if (mp->m_keys[mlen - keylen_mb_off] != c2) #else if (mp->m_keys[mlen] != typebuf.tb_buf[typebuf.tb_off + mlen]) @@ -2229,8 +2268,8 @@ vgetorpeek(advance) * - Full match: mlen == keylen * - Partly match: mlen == typebuf.tb_len */ - keylen = mp->m_keylen; - if (mlen == keylen + keylen = mp->m_keylen + keylen_mb_off; + if (mlen == keylen || (mlen == typebuf.tb_len && typebuf.tb_len < keylen)) { diff --git a/src/testdir/test_mapping.in b/src/testdir/test_mapping.in --- a/src/testdir/test_mapping.in +++ b/src/testdir/test_mapping.in @@ -35,7 +35,20 @@ o+ :nnoremap . :call feedkeys(".", "in")<cr> :/^a b 0qqdw.ifooqj0@q:unmap . - +:" langmap doesn't work with multibyte chars, that are mapped +:set langmap=öS +:nnoremap S s +/^MATCH HERE /e +ö: +:" langmap needs to allow for recursive mappings issue #297 +:nunmap S +:set langmap= +:set langmap=öc +:nnoremap col :.put ='Resolved langmap and mapping'<cr> +:/^# TEST 7/ +:" Needs feedkeys, test doesn't work with öol +:call feedkeys("öol", 't') +:nunmap S :/^test/,$w! test.out :qa! @@ -43,6 +56,13 @@ ENDTEST test starts here: +# TEST 5: let feedkeys insert chars at current position in mapping a b c d a b c d +# TEST 6: Apply mapping to langmapped multibyte char +MATCH HERE Do not replace. + +# TEST 7: Resolved langmaps need to be checked for mappings + + diff --git a/src/testdir/test_mapping.ok b/src/testdir/test_mapping.ok --- a/src/testdir/test_mapping.ok +++ b/src/testdir/test_mapping.ok @@ -1,7 +1,15 @@ test starts here: +# TEST 5: let feedkeys insert chars at current position in mapping fooc d fooc d + +# TEST 6: Apply mapping to langmapped multibyte char +MATCH HERE: Do not replace. + +# TEST 7: Resolved langmaps need to be checked for mappings +Resolved langmap and mapping + vim TEST2: CTRL-C |<ctrl-c>A|