2017-05-27 19:48 GMT+03:00 Bram Moolenaar <b...@moolenaar.net>: > > Nikolay Pavlov wrote: > >> 2017-05-27 18:02 GMT+03:00 Brett Stahlman <brettstahl...@gmail.com>: >> > On Sat, May 27, 2017 at 8:35 AM, Nikolay Aleksandrovich Pavlov >> > <zyx....@gmail.com> wrote: >> >> 2017-05-27 12:45 GMT+03:00 Bram Moolenaar <b...@moolenaar.net>: >> >>> >> >>> Nikolay Pavlov wrote: >> >>> >> >>>> 2017-05-26 20:43 GMT+03:00 Bram Moolenaar <b...@moolenaar.net>: >> >>>> > >> >>>> > Brett Stahlman wrote: >> >>>> > >> >>>> >> >> On Tuesday, May 23, 2017 at 8:25:33 AM UTC-5, Brett Stahlman >> >>>> >> >> wrote: >> >>>> >> >> > On Tue, May 23, 2017 at 4:35 AM, Bram Moolenaar >> >>>> >> >> > <b...@moolenaar.net> wrote: >> >>>> >> >> > > >> >>>> >> >> > > Brett Stahlman wrote: >> >>>> >> >> > > >> >>>> >> >> %--snip--% >> >>>> >> >> > > >> >>>> >> >> > > The best solution is probably to also add the raw rhs, with >> >>>> >> >> > > the terminal >> >>>> >> >> > > codes replaced. This won't work when changing the terminal >> >>>> >> >> > > type, but >> >>>> >> >> > > that is very unlikely to happen. >> >>>> >> >> > >> >>>> >> >> > You mean adding a key such as "raw_rhs" to the dictionary >> >>>> >> >> > returned by >> >>>> >> >> > maparg()? If so, then yes this would help, but there would >> >>>> >> >> > still need to >> >>>> >> >> > be a way to determine lhs, which is currently even more >> >>>> >> >> > ambiguous than >> >>>> >> >> > rhs. While it's true that I probably already have lhs if I'm >> >>>> >> >> > calling >> >>>> >> >> > maparg(), I need a way to determine which lhs(s) is/are >> >>>> >> >> > ambiguous with a >> >>>> >> >> > given lhs. Mapcheck() gives me only the rhs of the conflicting >> >>>> >> >> > map. To >> >>>> >> >> > save and restore, I'd need to know the lhs in canonical form as >> >>>> >> >> > well. >> >>>> >> >> >> >>>> >> >> Perhaps mapcheck() could take an optional arg requesting >> >>>> >> >> something more than a simple boolean return. When called with >> >>>> >> >> this extra arg, mapcheck() could return a conflicting/ambiguous >> >>>> >> >> lhs (or list thereof) in some canonical format (possibly >> >>>> >> >> determined by the value of the extra arg itself). As long as the >> >>>> >> >> format returned could be fed to maparg(), it would be possible to >> >>>> >> >> find conflicting mappings, remove them temporarily, and >> >>>> >> >> subsequently restore them... >> >>>> >> > >> >>>> >> > If you define a mapping you will want to know whether the mapping >> >>>> >> > already exists and needs to be restored. For that you can use >> >>>> >> > maparg(), >> >>>> >> > no need to use mapcheck(). >> >>>> >> > >> >>>> >> > Not sure why you would want to remove "conflicting" mappings. >> >>>> >> > Perhaps >> >>>> >> > when you map the ; key, and the user has ;x mapped? Then you >> >>>> >> > would need >> >>>> >> > a list. Adding a maplist() function would be better than adding >> >>>> >> > arguments to mapcheck(). >> >>>> >> >> >>>> >> Yes. Very much like that. I'm implementing a sort of transient mode, >> >>>> >> in >> >>>> >> which I'll "shadow" existing maps with very short (generally single >> >>>> >> character) mappings, which are expected to be ambiguous/conflicting >> >>>> >> with >> >>>> >> existing maps, and even builtin operators. Of course, when I exit the >> >>>> >> transient mode, I'd need to restore the mappings that were shadowed. >> >>>> >> >> >>>> >> The global and builtin maps are not a problem, since the transient >> >>>> >> maps use >> >>>> >> <buffer> and <nowait>; however, without parsing the output of one of >> >>>> >> the :map >> >>>> >> functions, I have no way of knowing which buf-local mappings will be >> >>>> >> ambiguous >> >>>> >> with the transient maps I'm defining. And parsing the :map output is >> >>>> >> problematic for the reasons already mentioned: e.g., no way to tell >> >>>> >> the >> >>>> >> difference between function key <F8> and the corresponding 4 >> >>>> >> characters. I'd >> >>>> >> actually considered taking some sort of iterative approach: e.g., >> >>>> >> trying all >> >>>> >> possible permutations of lhs as input to maparg() and testing the >> >>>> >> results, in >> >>>> >> an attempt to deduce the canonical form, but this would be extremely >> >>>> >> messy, >> >>>> >> and I don't even know whether it would be deterministic... The >> >>>> >> maplist() >> >>>> >> function you mentioned, if it returned all ambiguous left hand sides >> >>>> >> in >> >>>> >> canonical form, or even a list of the corresponding maparg()-style >> >>>> >> dictionaries, would be perfect. Of course, there would also need to >> >>>> >> be a way >> >>>> >> to get the rhs's canonical form: e.g., the extra "raw_rhs" key in >> >>>> >> the maparg() >> >>>> >> or maplist() dictionary. >> >>>> > >> >>>> > OK, so for this you would use maplist() to get the list of mappings to >> >>>> > disable, use maparg() to get the current mapping, clear the mapping, >> >>>> > do >> >>>> > your stuff, then restore the cleared mappings. You then need to make >> >>>> > sure you restore the mappings exactly as they were, even when your >> >>>> > "stuff" fails miserably. >> >>>> > >> >>>> > It's a lot easier if we would have a way to temporarily disable >> >>>> > mappings. It's mostly the same as above, but you won't need to use >> >>>> > maparg() to get the current mapping and the restore operation. >> >>>> > Instead >> >>>> > you would disable instead of clear, and later re-enable instead of >> >>>> > restore. Still need to make sure the re-enbling does happen, no >> >>>> > change >> >>>> > in that part. >> >>>> >> >>>> Not sure I understood what exactly you suggest to disable/restore. All >> >>>> mappings at once with one command? I would actually disagree here: I >> >>>> need something similar for translit3, but it only remaps >> >>>> single-character mappings, leaving most of other user mappings alone. >> >>>> One mapping at a time? It would be good, but given that request is >> >>>> temporary remapping naming the functionality enable/disable looks >> >>>> strange. And there are still issues with determining {lhs}. >> >>> >> >>> Let's use an example: Suppose a plugin has a special mode for entering >> >>> data (e.g. chemical formulas). It would then map some keys, e.g. "a". >> >>> If the user already has a mapping for "a" it needs to be restored when >> >>> leaving the special mode. If the user has mappings starting with "a" we >> >>> would like to disable those, to avoid the timeout waiting for the next >> >>> character. >> >>> >> >>> We do not want to disable mappings that don't interfere, to maximise the >> >>> freedom for the user to use other mappings at the same time. >> >>> >> >>>> One of the logical variants would be `:map <push> {lhs} >> >>>> {new-rhs}`/`:unmap <push> {lhs}`+`:map <pop> {lhs}`, but this is hard >> >>>> to implement and is rather limited, though less limited then >> >>>> enable/disable everything variant. >> >>> >> >>> This quickly gets complicated if we need to take into account all the >> >>> possible modes a mapping can be used in. >> >>> >> >>>> I would instead suggest a function mappings_dump()/mappings_add(): >> >>>> first is similar to `nvim[_buf]_get_keymap` and should dump all >> >>>> mappings as a list of maparg()-like dictionaries. Second should define >> >>>> mappings being given a list of them. Of course, this means that >> >>>> dictionaries need to be fixed to allow correctly saving/restoring. >> >>>> >> >>>> The advantages: >> >>>> >> >>>> 1. Easier to implement. Code for creating a maparg() dictionary is >> >>>> already there, iterating over all mappings is not a problem. Results >> >>>> needs to be incompatible with maparg() or use additional keys though: >> >>>> e.g. Neovim altered the contents of `noremap` and `buffer` keys: first >> >>>> is now 0, 1 or 2 (you can’t correctly restore a mapping if you can’t >> >>>> distinguish `map <script>` and `noremap`) and second is a buffer >> >>>> number or zero. >> >>>> 2. More flexible: you can save and restore everything, push or pop >> >>>> individual mappings, create a temporary mapping which is just like >> >>>> mapping X, but has `<Plug>(Translit3TemporaryMap)` lhs instead (to be >> >>>> returned from `<expr>` mappings in order to select either plugin >> >>>> behaviour or fall back to previously present user mapping instead). >> >>>> >> >>>> I can imagine other usages enable/disable or push/pop could not >> >>>> achieve: generating configuration with mappings like :mkvimrc, but >> >>>> allows doing adjustments (parsing `:mkvimrc` output is not fun, >> >>>> especially if you want to be forward compatible), creating a plugin >> >>>> which analyses how often different mappings are used (need to copy all >> >>>> mappings to temporary then replace existing mappings with plugin >> >>>> ones). >> >>>> 3. This is also forward compatible: just need to state in the >> >>>> documentation that new significant keys may be added in the future to >> >>>> the dictionaries so they should be preserved. >> >>> >> >>> I don't see much use for this. I can't think of a practical example how >> >>> a plugin manipulates mappings it didn't create itself or even knows what >> >>> they are for. >> >> >> >> Still Vim has :mkvimrc which does manipulate (dump) mappings from >> >> third-party plugins. Also I need this functionality for some <expr> >> >> mappings: if some condition is true (e.g. `>` is preceded by `-` (C, >> >> completion) or transliteration mode was enabled, or transliteration >> >> mode is enabled *and* character that does not start a new >> >> transliteration sequence is a continuation of previous one) use plugin >> >> mapping. If it is false, fall back to whatever was there previously, >> >> including falling back to whatever mapping was there previously. >> >> >> >> Also check https://github.com/neovim/neovim/issues/6123, this is the >> >> issue backing Neovim nvim_get_keymap() API function. >> >> >> >>> >> >>> Another complication is that mappings can be added/removed by other >> >>> mappings and by autocommands. >> >> >> >> I do not see how this complication is relevant to the discussion. I.e. >> >> I do not see how this complication should affect usage or >> >> implementation of both proposed changes. >> >> >> >>> >> >>> Disabling and re-enabling mappings is definitely more efficient than >> >>> removing and adding-back mappings. >> >> >> >> And it is also definitely both harder to implement and less flexible. >> > >> > Harder to implement, perhaps, but not necessarily less >> > flexible. Though the discussion thus far has centered mostly >> > on enable/disable functionality, there's nothing about the map >> > handle interface that limits it to this. It could support >> > query and execute functions, for instance. For cases in which >> > you wish to keep the original behavior, but need to "wrap" it >> > somehow, you could use the map handle to attach prolog/epilog >> > callback functions to a map. Presumably, such callback >> > functions (which could be either lambdas or funcrefs) would >> > accept an argument that allowed them to obtain information >> > about the original map, possibly even its exact lhs and rhs. >> > The prolog callback would be even more useful if Vim provided >> > a way (e.g., nonzero return) for it to abort the original map. >> >> Enable, disable, query, execute plus two callbacks. *Four* functions >> and two callbacks in place of just two simple functions, mostly using >> the functionality that is already there. Five if you remember about >> :mkvimrc and that somebody may want to replace that on top of new API: >> query will need a mirror function for creating a mapping then. > > You are completely missing the point: those two functions don't provide > the functionality we are talking about here.
Why do you think so? They provide everything what is needed to implement the functionality we are talking about here in VimL. > >> This is going to introduce a big amount of bugs just to add the >> flexibility which is naturally available through a much simpler >> approach. Emulating everything you mention on top of current VimL >> state plus mappings_dump()/mappings_load() / (mappings_clear()*) is >> not going to make plugins considerably slower (as long as you can >> operate on lists and use `map()`/`filter()`/etc: main VimL >> optimization principle is “the less Ex commands the faster the code”) >> and I do not see any other benefits, except for “with some handles >> implementation it may be slightly easier to pinpoint third-party >> plugins’ bugs”. >> >> * Found an issue in my proposal: `:execute 'unmap'` would not be easy >> or efficient to use, so additionally need either `mappings_clear({list >> to clear})` or make `mappings_load()` unmap mappings when rhs key is >> missing. >> >> > >> > Hmm... This may be overkill, but it might even be possible to >> > support the idea of a "virtual map handle": i.e., a handle not >> > to a specific map, but to a *set* of maps matching certain >> > criteria: e.g., <buffer>, <expr>, maps matching a mode mask, >> > maps starting with specific char(s), etc... Once such a >> > virtual handle had been obtained, a single call would suffice >> > to enable/disable, or even attach callbacks to all maps in the >> > set. Of course, some operations (e.g., execute) would be >> > permitted only on non-virtual (single map) handles. >> >> And this is just mappings_dump() + filter() with my approach without >> any need to invent a new DSL to describe criterias (or not invent DSL, >> but use VimL expressions which would be just as efficient as >> filter()). If I got it right then plus some way to attach callbacks to >> “new mapping defined” event to keep “callback attached” state. > > -- > Westheimer's Discovery: > A couple of months in the laboratory can > frequently save a couple of hours in the library. > > /// Bram Moolenaar -- b...@moolenaar.net -- http://www.Moolenaar.net \\\ > /// sponsor Vim, vote for features -- http://www.Vim.org/sponsor/ \\\ > \\\ an exciting new programming language -- http://www.Zimbu.org /// > \\\ help me help AIDS victims -- http://ICCF-Holland.org /// -- -- You received this message from the "vim_use" 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_use" group. To unsubscribe from this group and stop receiving emails from it, send an email to vim_use+unsubscr...@googlegroups.com. For more options, visit https://groups.google.com/d/optout.