/* Do not remove the headers from this file! see /USAGE for more info. */

/*
** bindings.c
**
** Handles key bindings in character mode.
**
** 95-May-20.  Rust.        Created.
*/

nomask void modal_push_char(function callback);	// M_INPUT


//:MODULE
//Implements character mode key bindings.

private nosave int escape_hit;
private nosave string matchstr = "";
private nosave mapping bindings;
private nosave function default_func;

private nomask void handle_one_char(int);

nomask void handle_input(string s)
{
  map(s, (: handle_one_char :));
}

private nomask int match_filter(string binding)
{
  return binding == matchstr;
}

private nomask int partial_match_filter(string binding)
{ 
  return strsrch(binding, matchstr) == 0;
}
  
private nomask void handle_one_char(int c)
{
  string* binding_matches;

  switch(c)
  {
     case '\t':
       matchstr += "<TAB>";
       break;
     case '\n':
     case '\r':
       matchstr += "<RET>";
       break;
     case 27:
       matchstr += "<ESC>";
       break;
     case 0:
       matchstr += "<DEL>";
       break;
     case 1..8:
     case 11..12:
     case 14..26:
       matchstr = sprintf("%s<CTRL-%c>",matchstr,(c-1+'a'));
       break;
     default:
       matchstr = sprintf("%s%c",matchstr,c);
       break;
  }
  binding_matches = filter_array(keys(bindings), (: match_filter :));
   if(sizeof(binding_matches))
  {
    evaluate(bindings[matchstr], matchstr);
    matchstr = "";
    return;
  }
// Now check for a partial match, in which case we hold off...

  binding_matches = filter_array(keys(bindings), (:partial_match_filter:));
  if(sizeof(binding_matches))
     return;

  evaluate(default_func, matchstr);
  matchstr = "";

}

//:FUNCTION init_charmode
//start up character mode, passing a map of bindings and a 
//function to handle keystrokes not covered in the binding map.

nomask void init_charmode(mapping new_bindings, function d)
{
// add a binding for < so that a < won't hold waiting for the ESC>
// of course, you can bind over this.
    bindings = ([ "<" : d ]) + new_bindings;
    default_func = d;
    modal_push_char((: handle_input :));
}

//:FUNCTION bind
//Add a key binding to a charmode shell.
nomask void bind(string sequence, function callback)
{
    bindings[sequence] = callback;
}

//:FUNCTION unbind
//Remove a key binding from a charmode shell.
nomask void unbind(string sequence)
{
    map_delete(bindings, sequence);
}
