Hi

A few comments inline:

> diff --git a/format.c b/format.c
> index 6f988b9ac2cc..8630aabed5d7 100644
> --- a/format.c
> +++ b/format.c
> @@ -435,7 +435,8 @@ format_client(struct format_tree *ft, struct client *c)
>       *strchr(tim, '\n') = '\0';
>       format_add(ft, "client_activity_string", "%s", tim);
>  
> -     format_add(ft, "client_prefix", "%d", !!(c->flags & CLIENT_PREFIX));
> +     format_add(ft, "client_prefix", strcmp(c->keytable->name, "root") ? 
> "1": "0");
> +     format_add(ft, "client_keytablename", "%s", c->keytable->name);

Let's call it client_key_table to fit the style of most of the others.

>  
>       if (c->tty.flags & TTY_UTF8)
>               format_add(ft, "client_utf8", "%d", 1);
> diff --git a/key-bindings.c b/key-bindings.c
> index 58be0c6fe896..d391744a1bff 100644
> --- a/key-bindings.c
> +++ b/key-bindings.c
> @@ -24,61 +24,143 @@
>  
>  #include "tmux.h"
>  
> +struct key_table      *key_bindings_lookup_table_noref(const char *, int);
> +
>  RB_GENERATE(key_bindings, key_binding, entry, key_bindings_cmp);
> +RB_GENERATE(key_tables, key_table, entry, key_table_cmp);
> +
> +struct key_tables    key_tables;
>  
> -struct key_bindings  key_bindings;
> +int
> +key_table_cmp(struct key_table *e1, struct key_table *e2)
> +{
> +     return strcmp(e1->name, e2->name);
> +}
>  
>  int
>  key_bindings_cmp(struct key_binding *bd1, struct key_binding *bd2)
>  {
> -     int     key1, key2;
> -
> -     key1 = bd1->key & ~KEYC_PREFIX;
> -     key2 = bd2->key & ~KEYC_PREFIX;
> -     if (key1 != key2)
> -             return (key1 - key2);
> -
> -     if (bd1->key & KEYC_PREFIX && !(bd2->key & KEYC_PREFIX))
> -             return (-1);
> -     if (bd2->key & KEYC_PREFIX && !(bd1->key & KEYC_PREFIX))
> -             return (1);
> -     return (0);
> +     return (bd1->key - bd2->key);
>  }
>  
> -struct key_binding *
> -key_bindings_lookup(int key)
> +struct key_table *
> +key_bindings_lookup_table_noref(const char *name, int create)
>  {
> -     struct key_binding      bd;
> +     struct key_table         table_search;
> +     struct key_table        *table;
>  
> -     bd.key = key;
> -     return (RB_FIND(key_bindings, &key_bindings, &bd));
> +     table_search.name = name;
> +     table = RB_FIND(key_tables, &key_tables, &table_search);
> +     if (table)
> +             return table;
> +
> +     if (!create)
> +             return NULL;
> +
> +     table = xmalloc(sizeof *table);
> +     table->name = table->name_for_free = xstrdup(name);
> +     RB_INIT(&(table->key_bindings));
> +     /* for key_tables */
> +     table->references = 1;
> +     RB_INSERT(key_tables, &key_tables, table);
> +
> +     return table;
> +}
> +
> +struct key_table *
> +key_bindings_lookup_table(const char *name, int create)

I don't think it is intuitive for a lookup function to take a
reference. I would do without this function and just do lookup followed
by table->references++ in the caller.

Personally I would also split this into two functions, one for lookup
and one for create and do this in the caller if create is needed:

        t = key_bindings_lookup_table("foo");
        if (t == NULL)
                t = key_bindings_create_table("foo");

But if you prefer a create flag that is probably okay, although in that
case I'd rather not call the function _lookup_table. Maybe _get_table
instead?

> +{
> +     struct key_table        *table;
> +
> +     table = key_bindings_lookup_table_noref(name, create);
> +     if (!table)
> +             return NULL;
> +
> +     table->references++;
> +     return table;
>  }
>  
>  void
> -key_bindings_add(int key, int can_repeat, struct cmd_list *cmdlist)
> +key_bindings_unreference_table(struct key_table *table)

I'd do s/unreference/unref/ here to make this a bit less of a mouthful.

>  {
>       struct key_binding      *bd;
>  
> -     key_bindings_remove(key);
> +     if (--table->references == 0) {
> +             while (!RB_EMPTY(&(table->key_bindings))) {
> +                     bd = RB_ROOT(&(table->key_bindings));
> +                     RB_REMOVE(key_bindings, &(table->key_bindings), bd);
> +                     cmd_list_free(bd->cmdlist);
> +                     free(bd);
> +             }
> +             free(table->name_for_free);
> +             free(table);
> +     }
> +}
> +
> +void
> +key_bindings_add(const char *name, int key, int can_repeat, struct cmd_list 
> *cmdlist)
> +{
> +     struct key_table                *table;
> +     struct key_binding               bd_search;
> +     struct key_binding              *bd;
> +
> +     table = key_bindings_lookup_table_noref(name, 1);
> +
> +     bd_search.key = key;
> +     bd = RB_FIND(key_bindings, &(table->key_bindings), &bd_search);
> +     if (bd != NULL) {
> +             RB_REMOVE(key_bindings, &(table->key_bindings), bd);
> +             cmd_list_free(bd->cmdlist);
> +             free(bd);
> +     }
>  
>       bd = xmalloc(sizeof *bd);
>       bd->key = key;
> -     RB_INSERT(key_bindings, &key_bindings, bd);
> +     RB_INSERT(key_bindings, &(table->key_bindings), bd);
>  
>       bd->can_repeat = can_repeat;
>       bd->cmdlist = cmdlist;
>  }
>  
>  void
> -key_bindings_remove(int key)
> +key_bindings_remove(const char *name, int key)
>  {
> -     struct key_binding      *bd;
> +     struct key_table                *table;
> +     struct key_binding               bd_search;
> +     struct key_binding              *bd;
>  
> -     if ((bd = key_bindings_lookup(key)) == NULL)
> +     table = key_bindings_lookup_table_noref(name, 0);
> +     if (!table)
>               return;
> -     RB_REMOVE(key_bindings, &key_bindings, bd);
> +
> +     bd_search.key = key;
> +     bd = RB_FIND(key_bindings, &(table->key_bindings), &bd_search);
> +     if (!bd)
> +             return;
> +
> +     RB_REMOVE(key_bindings, &(table->key_bindings), bd);
>       cmd_list_free(bd->cmdlist);
>       free(bd);
> +
> +     if (RB_EMPTY(&(table->key_bindings))) {
> +             RB_REMOVE(key_tables, &key_tables, table);
> +             /* This represents key_tables's reference */

I don't think we need these comments. If you feel it needs to be
documented that the tree holds a reference, put a comment once either
with the references member in the struct in tmux.h or somewhere around
where the tree is declared.

> +             key_bindings_unreference_table(table);
> +     }
> +}
> +
> +void
> +key_bindings_remove_table(const char *name)
> +{
> +     struct key_table        *table;
> +
> +     table = key_bindings_lookup_table_noref(name, 0);
> +     if (!table)
> +             return;
> +
> +     RB_REMOVE(key_tables, &key_tables, table);
> +     /* This represents key_tables's reference */
> +     key_bindings_unreference_table(table);
>  }
>  
>  void
> @@ -167,7 +249,7 @@ key_bindings_init(void)
>       struct cmd      *cmd;
>       struct cmd_list *cmdlist;
>  
> -     RB_INIT(&key_bindings);
> +     RB_INIT(&key_tables);
>  
>       for (i = 0; i < nitems(table); i++) {
>               cmdlist = xcalloc(1, sizeof *cmdlist);
> @@ -183,7 +265,7 @@ key_bindings_init(void)
>               TAILQ_INSERT_HEAD(&cmdlist->list, cmd, qentry);
>  
>               key_bindings_add(
> -                 table[i].key | KEYC_PREFIX, table[i].can_repeat, cmdlist);
> +                 "prefix", table[i].key, table[i].can_repeat, cmdlist);
>       }
>  }
>  
> diff --git a/server-fn.c b/server-fn.c
> index e0859f707034..6f3491693d76 100644
> --- a/server-fn.c
> +++ b/server-fn.c
> @@ -101,6 +101,13 @@ server_status_client(struct client *c)
>  }
>  
>  void
> +server_keytable_client(struct client *c, const char *name)
> +{
> +     key_bindings_unreference_table(c->keytable);
> +     c->keytable = key_bindings_lookup_table(name, 1);

I'm not convinced we need this helper function for two lines.

> +}
> +
> +void
>  server_redraw_session(struct session *s)
>  {
>       struct client   *c;
> diff --git a/tmux.h b/tmux.h
> index f9d6087ab714..dcd2c8d25f44 100644
> --- a/tmux.h
> +++ b/tmux.h
> @@ -164,10 +164,9 @@ extern char   **environ;
>  #define KEYC_ESCAPE 0x2000
>  #define KEYC_CTRL 0x4000
>  #define KEYC_SHIFT 0x8000
> -#define KEYC_PREFIX 0x10000
>  
>  /* Mask to obtain key w/o modifiers. */
> -#define KEYC_MASK_MOD (KEYC_ESCAPE|KEYC_CTRL|KEYC_SHIFT|KEYC_PREFIX)
> +#define KEYC_MASK_MOD (KEYC_ESCAPE|KEYC_CTRL|KEYC_SHIFT)
>  #define KEYC_MASK_KEY (~KEYC_MASK_MOD)
>  
>  /* Other key codes. */
> @@ -1298,7 +1297,7 @@ struct client {
>       struct screen    status;
>  
>  #define CLIENT_TERMINAL 0x1
> -#define CLIENT_PREFIX 0x2
> +/* replaced by keytablename: #define CLIENT_PREFIX 0x2 */

Just remove this and either renumber the rest or put a comment /* 0x2
unused */.

>  #define CLIENT_EXIT 0x4
>  #define CLIENT_REDRAW 0x8
>  #define CLIENT_STATUS 0x10
> @@ -1317,6 +1316,7 @@ struct client {
>  #define CLIENT_256COLOURS 0x20000
>  #define CLIENT_IDENTIFIED 0x40000
>       int              flags;
> +     struct key_table *keytable;
>  
>       struct event     identify_timer;
>  
> @@ -1444,6 +1444,22 @@ struct key_binding {
>       RB_ENTRY(key_binding) entry;
>  };
>  RB_HEAD(key_bindings, key_binding);
> +struct key_table {
> +     /*
> +      * Search needs to be able to use const char * and free needs to be
> +      * able to free the name we allocated when we put it in the tree for
> +      * real.  Search and keying is done by name, free is done with
> +      * name_for_free.
> +      */
> +     const char               *name;
> +     char                     *name_for_free;

Don't do this, it's confusing. Just use a const char * and cast it to
void * when you pass it to free.

> +     struct key_bindings      key_bindings;
> +
> +     u_int                    references;
> +
> +     RB_ENTRY(key_table) entry;
> +};
> +RB_HEAD(key_tables, key_table);
>  
>  /*
>   * Option table entries. The option table is the user-visible part of the
> @@ -1865,12 +1881,16 @@ int   cmd_string_parse(const char *, struct cmd_list 
> **, const char *,
>  int  client_main(int, char **, int);
>  
>  /* key-bindings.c */
> -extern struct key_bindings key_bindings;
> -int   key_bindings_cmp(struct key_binding *, struct key_binding *);
>  RB_PROTOTYPE(key_bindings, key_binding, entry, key_bindings_cmp);
> -struct key_binding *key_bindings_lookup(int);
> -void  key_bindings_add(int, int, struct cmd_list *);
> -void  key_bindings_remove(int);
> +RB_PROTOTYPE(key_tables, key_table, entry, key_table_cmp);
> +extern struct key_tables key_tables;
> +int   key_table_cmp(struct key_table *, struct key_table *);
> +int   key_bindings_cmp(struct key_binding *, struct key_binding *);
> +struct        key_table *key_bindings_lookup_table(const char *, int);
> +void          key_bindings_unreference_table(struct key_table *);
> +void  key_bindings_add(const char *, int, int, struct cmd_list *);
> +void  key_bindings_remove(const char *, int);
> +void  key_bindings_remove_table(const char *);
>  void  key_bindings_init(void);
>  void  key_bindings_dispatch(struct key_binding *, struct client *);
>  
> @@ -1906,6 +1926,7 @@ void     server_write_session(struct session *, enum 
> msgtype, const void *,
>            size_t);
>  void  server_redraw_client(struct client *);
>  void  server_status_client(struct client *);
> +void  server_keytable_client(struct client *, const char *);
>  void  server_redraw_session(struct session *);
>  void  server_redraw_session_group(struct session *);
>  void  server_status_session(struct session *);
> -- 
> 1.9.1
> 
> 
> ------------------------------------------------------------------------------
> "Accelerate Dev Cycles with Automated Cross-Browser Testing - For FREE
> Instantly run your Selenium tests across 300+ browser/OS combos.
> Get unparalleled scalability from the best Selenium testing platform available
> Simple to use. Nothing to install. Get started now for free."
> http://p.sf.net/sfu/SauceLabs
> _______________________________________________
> tmux-users mailing list
> tmux-users@lists.sourceforge.net
> https://lists.sourceforge.net/lists/listinfo/tmux-users

------------------------------------------------------------------------------
"Accelerate Dev Cycles with Automated Cross-Browser Testing - For FREE
Instantly run your Selenium tests across 300+ browser/OS combos.
Get unparalleled scalability from the best Selenium testing platform available
Simple to use. Nothing to install. Get started now for free."
http://p.sf.net/sfu/SauceLabs
_______________________________________________
tmux-users mailing list
tmux-users@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/tmux-users

Reply via email to