On Fri, Feb 18, 2011 at 04:12:47PM +1100, Ben Schmidt wrote:
> >Plus, it's only the queue of incoming keypresses - that queue isn't
> >going to stay very big for very long.
> 
> It's not just the input queue that's in question here, it's everywhere
> in Vim where keypresses are represented. For instance, the right hand
> sides of mappings are not primarily characters, but lists of keypresses.
> They need the same amount of expressive power to work properly.

Yes. And the scheme I created is no less expressive than the byte
queues. In fact it is more expressive, able to disambiguate neatly
situations that cannot normally be represented - see also my other mail
on the thread a few minutes ago.

  http://groups.google.com/group/vim_dev/msg/7bb4cc9b127cddb3

> When macros are recorded, registers, which usually are primarily lists
> of characters, are used to store keypresses. Likewise, for feedkeys() to
> work, its input, a string, needs to be able to represent keypresses.
> 
> And I'm sure there are plenty more subtleties.

Yes - again, my point of these structures is that they exactly _do_
represent these keypresses.

> The bottom line, though, is that changing to a struct-based approach
> could make the job absolutely huge, requiring reworking and/or
> redesigning how maps, registers, etc. all work. And it might not even be
> possible since, e.g. registers need to be able to do both characters and
> keys.

But every character -can- be represented as a key - namely, the key that
generates it. Let me again repeat my structure:

  struct keypress {
    unsigned int is_special : 1;
    unsigned int modifiers  : 10;
    unsigned int codepoint  : 21;
  };

Any character has a Unicode codepoint (cp). That's represented by

  { 0, 0, cp }

Any keypress has a symbolic key number, taken from some arbitrary
enumeration - I care not where.

 { 1, mod, key }

Now, we can also represent those modified Unicode keys such as Ctrl-I
and Shift-Space which previously were impossible:

 { 0, MOD_CTRL, 'i' }    /* Ctrl-I */
 { 0, MOD_SHIFT, ' ' }   /* Shift-Space */

> It would be much simpler to extend the current approach which uses
> an 'escape mechanism' for representing special keys. Just hit qq and
> type some arrow keys, q to end recording, and then inspect register q
> and you'll see what's going on here. Vim uses a byte <80> followed by
> two more bytes to represent special keys.
> 
> IMHO, what needs to be done is for this to be tidied up and made
> consistent and documented so that these codes can be more readily
> generated, interpreted, and even viewed and understood by users (e.g.
> when I do :registers, it would be nice to see <S-Up> rather than
> <80><fd>^D, when appropriate). Included in this is a clear specification
> of what control characters mean, e.g. does ^I (<09>) mean tab or
> control-I? And which of those keys can or does use the escape mechanism?

OK - well, if you feel confident that the existing prefix-escape
mechanism can completely an unambiguously represent all these possible
keystrokes, then sure, that way might result in less code change
overall.

But do make quite sure it can represent them. Specifically consider the
two tricky special-cases I suggested - repeated here again:

  Tab                      { 1, 0, KEY_TAB }
  Ctrl-I                   { 0, MOD_CTRL, 'i' }
  Ctrl-Shift-I             { 0, MOD_CTRL, 'I' }

  Escape C                 { 1, 0, KEY_ESCAPE }, { 0, 0, 'C' }
  Alt+C                    { 0, MOD_ALT, 'C' }
  é                        { 0, 0, 0xe9 } 

> Then the behaviour of mappings needs to be defined--if there is a
> mapping for ^I (<09>) and I push tab, will it be triggered? If in a
> terminal which can't distinguish control-I and tab, and a ^I is
> received, should the mapping for Tab or control-I be triggered? If
> there's a mapping for ^I as well as Tab, which has precedence?

I propose a pair of boolean settings, with the following defaults:

 :set nomodifiedunicode
 :set altisescape

Under these settings, 

  :map <Ctrl-I> ... vs  :map <Tab> ...  shall have the same effect, each
    overwriting the effects of the other; last one wins.

  Pressing the Tab key or Ctrl-I shall both invoke the last mapping
    registered.

  :map <Escape>C ... vs  :map <Alt+C> ... shall behave similarly, each
    overwrites the other. Typing either key sequence will invoke the
    last map to be registered.

If a user decides "I want to use those extra Ctrl- keys", they can set
in their .vimrc

  :set modifiedunicode

At this point,

  :map <Ctrl-I> and :map <Tab>  shall fill two -different-
    slots of the mapping list, and typing either key will activate the
    indicated mapping.

If a user further decides "I want the Alt modifier to not mean Escape
prefixing", then

  :set noaltisescape

At which point,

  :map <Escape>C and :map <Alt+C> shall also be different.

The only remaining ambiguity to be answered is, what happens in the
following case:

  :set nomodifiedunicode
  :map <Tab> ONE
  :map <Ctrl-I> TWO
  :set modifiedunicode

  now press Tab or Ctrl-I

I don't have an easy answer for this case; no particular behaviour jumps
out at me as "obviously correct".

> All these
> kinds of questions need clear answers, and sensible specifications and
> design need to address them, avoid ambiguity, and take care to require
> as little as possible work for users, plugin authors, etc. to update
> their code and mappings.
> 
> Then the input code needs to be reworked in all the GUIs and in the
> terminal handling to generate the appropriate internal codes,
> consistently across all the different GUIs, etc., in line with that
> specification/design.

I propose that the structure approach makes this simpler. It is now
clearly obvious how e.g. GTK should fill in these structures, as GDK
keypress events already have unicode / modifier bits or symbolic keys.
It's also obvious how to render such a structure as a string, possibly
wrapping <> around it, possibly prefixing C- or A- or whatever as
appropriate.

(( This sort of behaviour is already implemented by libtermkey, even
   going so far as to support

    char buffer[256];
    termkey_snprint_key(tk, buffer, sizeof buffer, &key, TERMKEY_FORMAT_VIM);

   for exactly this purpose. :) ))


-- 
Paul "LeoNerd" Evans

[email protected]
ICQ# 4135350       |  Registered Linux# 179460
http://www.leonerd.org.uk/

Attachment: signature.asc
Description: Digital signature

Raspunde prin e-mail lui