%
%  Example of menus for JED.  This is designed to aid in learning
%  the editor since after a menu item has been chosen, the user is 
%  informed of the keybinding of the function.
%


define menu_build_display_string (list)
{
   variable i = 0, cmd, s = Null_String;
   
   forever 
     {
	cmd = extract_element (list, i, ',');
	!if (strlen(cmd)) break;
	if (i) s = strcat(s, ", ");
	s = Sprintf("%s(%d)%s", s, i, cmd, 3);
	++i;
     }
   s;
}


define menu_list_length (list)
{
   variable i = 0;
   
   i - 1;
}

variable Menu_Last_Cmd;
variable Menu_Abort;  Menu_Abort = 0;

define menu_select_cmd (s_list, cmd_list)
{
   variable cmd, i, s, n;
   i = 0;
  
   n = 0; while (strlen(extract_element(cmd_list, n, ','))) n++;
   n--;
  
   s = strcat ("Menu: ", menu_build_display_string(s_list));
   
   
   do
     {
	Menu_Abort = 0;

	forever 
	  {
	     flush(s);
	     i = getkey();
	     if (i == 7) call ("kbd_quit");
	     if (i == ' ')
	       {
		  Menu_Abort = 1;
		  return;
	       }

	     i -= '0';
  
	     if ((i >= 0) and (i <= n)) break;
    

	     beep();
	     flush_input();
	     flush("Pick a number or press Ctrl-G to abort or SPACE to go back.");
	     pop(input_pending(20));
	  }
   
	cmd = extract_element(cmd_list, i, ',');
  
	if (int (substr(cmd, 1, 1)) == '@')
	  {	
	     Menu_Last_Cmd = substr(cmd, 2, strlen(cmd));
	     call (Menu_Last_Cmd);
	  }
	else
	  {
	     Menu_Last_Cmd = cmd;
	     eval(cmd);
	  }
     }
   while(Menu_Abort);
}

define menu_window_cmds ()
{
   menu_select_cmd ("One window,Split Window,Other Window,Del Window,Redraw",
		    "@one_window,@split_window,@other_window,@delete_window,@redraw");
}


define search_replace ()
{
   menu_select_cmd ("Search Forward,Search Backward,Replace",
		    "search_forward,search_backward,replace_cmd");
}


define menu_deletion_cmd ()
{
   menu_select_cmd ("Delete Char,Delete Word",
		    "del,@delete_word");
}



define menu_cut_paste ()
{
   menu_select_cmd ("Deleting,Begin Region,Cut Region,Copy Region,Paste",
		    "menu_deletion_cmd,@set_mark_cmd,@kill_region,@copy_region,@yank");
}



define menu_movement ()
{
   menu_select_cmd ("Page Up,Page Down,Top,Bottom,Page Left,Page Right",
		    "@page_up,@page_down,@beg_of_buffer,@end_of_buffer,@scroll_right,@scroll_left");
}



define menu_buffer_modes ()
{
   menu_select_cmd ("C-Mode,Text-Mode,No-Mode,Fortran-Mode",
		    "c_mode,text_mode,no_mode,fortran");
}

define menu_basics ()
{
   menu_select_cmd ("Search/Replace,Movement,Cut/Paste,Undo,Formatting",
		    "search_replace,menu_movement,menu_cut_paste,@undo,@format_paragraph");
}


define menu_buffers ()
{
   menu_select_cmd ("Kill Buffer,Switch To Buffer,List Buffers,Set buffer modes",
		    "@kill_buffer,@switch_to_buffer,list_buffers,menu_buffer_modes");
}


define menu_files ()
{
   menu_select_cmd ("Open File,Save to File,Save Buffers,Insert File",
		    "@find_file,@write_buffer,@save_buffers,@insert_file");
}



define menu_help ()
{
   menu_select_cmd ("Pop up help,Browse Documentation,Show Key,Where is Command",
		    "help,info_mode,showkey,where_is");
}


define menu_misc ()
{
   menu_select_cmd ("compose mail,send mail,ispell,shell command,Suspend",
		    "mail,send,ispell,do_shell_cmd,@sys_spawn_cmd");
}



define menu_main_cmds ()
{
   variable n, key, len, next, nlen;
   
   menu_select_cmd ("Basic,Files,Buffers,Windows,Help,Misc,Exit",
		    "menu_basics,menu_files,menu_buffers,menu_window_cmds,menu_help,menu_misc,@exit_jed");

     %
     %  Show user keybinding of the function.
     %  The problem with this is that any function which leaves a message
     %  in the message buffer, the message will be destroyed.  Here I 
     %  update screen and sleep for a second before continuing.  Menus are
     %  intrinsically inefficient anyway.
     %
  
   if (strlen(MESSAGE_BUFFER))
     { 
	update (0);
	input_pending(20); pop();
     }
   
   if (Menu_Abort)
     { 
	flush (" ");
	return; 
     }
   
   if (n = which_key (Menu_Last_Cmd), n)
     {
	=key; n--;
	
	len = strlen (key);
	loop (n)
	  {
	     =next;
	     nlen = strlen (next);
	     if (nlen < len)
	       {
		  len = nlen;
		  key = next;
	       }
	  }

	Sprintf ("%s is on key %s", Menu_Last_Cmd, expand_keystring (key), 2);
     }
   else strcat (Menu_Last_Cmd, " is not on any keys.");
   message (());
}


