I've recently put together a few new features and updates for GNU Screen, in a (transient?) fork called tscreen[0]. This is primarily because I've always had the belief that GNU Screen was not being actively developed - but also because there are things that I personally would like to see added, changed, or dropped.
One of the most interesting new features is the ability to define aliases. In my current implementation there are two kinds of aliases: 1. Mere synonyms. 2. Constant calls to other functions with a list of arguments. As an example the following makes "shout" an alias for "echo": alias shout echo A more interesting alias is one with some actual activity behind it. This is a typical example in four parts: # # 1. Caption toggle # alias caption_off eval "caption splitonly" alias caption_on eval "caption always" # # 2. Statusbar toggle # alias status_off eval "hardstatus ignore" alias status_on eval "hardstatus alwayslastline" # # 3. Disable both caption and status, and show a message. # alias fullscreen eval "status_off" "caption_off" "echo 'fullscreen - \"Ctrl-a F\" to return'" alias captioned eval "status_on" "caption_on" "echo 'fullscreen - \"Ctrl-a f\" for fullscreen'" # # 4. Bind the keys # bind f eval fullscreen bind F eval captioned In terms of implementation the code is pretty straightforward, and some of the actual details show through. We maintain a global linked list of aliases. The structure is : /* * Command aliases. */ struct alias { /* next in our linked list */ struct alias *next; char *alias_name; char *alias_value; int alias_arg_count; char **alias_args; }; For the simple case we have an entry of the form: alias{ alias_name => "shout", alias_value => "echo", } For a more complex case we'd have this: alias{ alias_name => "fullscreen" alias_value => "eval", alias_args => [ "status_off", "caption_off", "echo 'blah'" ], alias_args_count => 3 } As you can see this alias is in two parts: 1. It defines "fullscreen" as actually invoking "eval". 2. When fullscreen is called it will invoke eval with the list of three arguments we've been passed at create time. Anyway, Juergen Weigert, suggested I drop the list a mail with a couple of comments. I hope this serves as a suitable introduction, and the patch is attached - against the current git tree. Steve -- Managed Anti-Spam Service http://mail-scanning.com/ 0 - http://www.steve.org.uk/Software/tscreen/
diff --git a/src/comm.c b/src/comm.c index 27f67c7..29cecb9 100644 --- a/src/comm.c +++ b/src/comm.c @@ -51,6 +51,7 @@ struct comm comms[RC_LAST + 1] = #ifdef MULTIUSER { "addacl", ARGS_1234 }, #endif + { "alias", ARGS_12|ARGS_ORMORE }, { "allpartial", NEED_DISPLAY|ARGS_1 }, { "altscreen", ARGS_01 }, { "at", NEED_DISPLAY|ARGS_2|ARGS_ORMORE }, diff --git a/src/extern.h b/src/extern.h index 3e64b7f..bfb4ee1 100644 --- a/src/extern.h +++ b/src/extern.h @@ -178,6 +178,10 @@ extern int OpenPTY __P((char **)); extern void InitPTY __P((int)); /* process.c */ +extern void AddAlias( const char *name, const char *val , char **args, int count); +struct alias * FindAlias( char *name ); +extern void DelAlias( const char *name ); + extern void InitKeytab __P((void)); extern void ProcessInput __P((char *, int)); #ifdef MAPKEYS diff --git a/src/process.c b/src/process.c index 79cb716..e231574 100644 --- a/src/process.c +++ b/src/process.c @@ -224,6 +224,20 @@ static int maptimeout = 300; #endif +/* + * Command aliases. + */ +struct alias { + /* next in our linked list */ + struct alias *next; + char *alias_name; + char *alias_value; + int alias_arg_count; + char **alias_args; +}; +struct alias *g_aliases_list = NULL; + + /* digraph table taken from old vim and rfc1345 */ static const unsigned char digraphs[][3] = { {' ', ' ', 160}, /* ? */ @@ -2516,6 +2530,14 @@ int key; break; case RC_SLEEP: break; /* Already handled */ + case RC_ALIAS: + if (argc > 2 ) + AddAlias( args[0], args[1], args+2, argc-2); + if (argc == 2 ) + AddAlias( args[0], args[1], NULL, 0); + if ( argc == 1 ) + DelAlias( args[0] ); + break; case RC_TERM: s = NULL; if (ParseSaveStr(act, &s)) @@ -4254,12 +4276,57 @@ int key; } void +DoAlias( argv, argl ) +char **argv; +int *argl; +{ + struct action act; + + /* Find the alias */ + struct alias *alias = FindAlias( *argv ); + + if ( alias == NULL ) + { + Msg(0, "internal error alias not found" ); + return; + } + + act.nr = FindCommnr( alias->alias_value); + + if ( act.nr == RC_ILLEGAL ) + { + Msg(0, "illegal alias value - aliases to aliases don't work (yet)."); + return; + } + if ( alias->alias_arg_count > 0 ) + { + act.args = alias->alias_args; + act.argl = &(alias->alias_arg_count); + } + else + { + act.args = argv + 1; + act.argl = argl + 1; + } + + DoAction(&act, -1); +} + + +void DoCommand(argv, argl) char **argv; int *argl; { struct action act; + + /* + *Alias? + */ + if ( FindAlias( *argv ) != NULL ) + return DoAlias( argv, argl ); + if ((act.nr = FindCommnr(*argv)) == RC_ILLEGAL) { Msg(0, "%s: unknown command '%s'", rc_name, *argv); @@ -6413,6 +6480,130 @@ char *presel; return wi; } + + +/** + * Add an alias + */ +void AddAlias( name, value, args, count ) + const char *name; + const char *value; + char **args; + int count; +{ + struct alias *new = NULL; + + /* Make sure the alias maps to something */ + if ( FindCommnr( (char *)value ) == RC_ILLEGAL ) + { + Msg(0, "illegal alias value - aliases to aliases don't work (yet)."); + return; + } + + /* Make sure we don't already have this alias name defined. */ + if ( FindAlias( (char *)name ) != NULL ) + { + Msg(0, "alias already defined: %s", name); + return; + } + + + new = (struct alias *)malloc(sizeof(struct alias)); + + /* store it */ + new->next = NULL; + new->alias_name = strdup( name ); + new->alias_value = strdup( value ); + new->alias_arg_count = count; + new->alias_args = NULL; + + if ( count >0) + { + int i; + new->alias_args = (char **)malloc(sizeof(char *)*count+1); + for ( i = 0; i< count; i++ ) + { + new->alias_args[i] = strdup( args[i]); + } + new->alias_args[i] = NULL; + } + + /* Add to head */ + { + new->next = g_aliases_list; + g_aliases_list = new; + } +} + + +/** + * Find an alias. + */ +struct alias * +FindAlias( name ) + char *name; +{ + struct alias *t = g_aliases_list; + + while( t != NULL ) + { + if ( ( t->alias_name != NULL ) && + ( strcmp(t->alias_name, name) == 0 ) ) + return t; + + t = t->next; + } + + return NULL; +} + + + +/** + * Delete an alias + */ +void DelAlias( name ) + const char *name; +{ + + /* Find the previous alias */ + struct alias *cur = g_aliases_list; + struct alias *prev = g_aliases_list; + + while( cur != NULL ) + { + if ( ( cur->alias_name != NULL ) && + ( strcmp(cur->alias_name, name) == 0 ) ) + { + struct alias *found = cur; + int c; + + /* remove this one from the chain. */ + prev->next = found->next; + + free( found->alias_name ); + free( found->alias_value ); + if ( found->alias_arg_count > 0 ) + { + for ( c = 0; c <= found->alias_arg_count ; c++) + free(found->alias_args[c] ); + free(found->alias_args); + } + free( cur ); + + Msg(0, "alias %s removed", name ); + + } + prev = cur; + cur = cur->next; + } + + Msg(0, "alias %s not found", name ); + +} + + + #if 0 /* sorted list of all commands */