[gnu.bash.bug] Question about vi-mode

night@pawl.rpi.edu (Trip Martin) (11/09/89)

I realize this group is for bash bugs, but I couldn't find any other
group which was more suitable.  My apologies if this is the wrong group.

I just got bash up and running on a 3B2, and looking through the
documentation, I noticed that the only way to enter vi-mode is by
having a .inputrc when the program is first run.  There are times when
I would like to be able to switch to vi-mode after bash is already
running.  Why is the extra rc file (.inputrc) necessary, and why is
that the only way to enter vi-mode?  


Trip Martin  KA2LIV       night@pawl.rpi.edu
Finite state machinist    night@uruguay.acm.rpi.edu
-- 
Trip Martin  KA2LIV       night@pawl.rpi.edu
Finite state machinist    night@uruguay.acm.rpi.edu

bfox%vision@HUB.UCSB.EDU (Brian Fox) (11/11/89)

   Posted-Date: 9 Nov 89 02:38:42 GMT
   Date: 9 Nov 89 02:38:42 GMT
   From: rpi!night@cis.ohio-state.edu  (Trip Martin)
   Organization: Rensselaer Polytechnic Institute, Troy NY
   Sender: bug-bash-request@prep.ai.mit.edu

   I just got bash up and running on a 3B2, and looking through the
   documentation, I noticed that the only way to enter vi-mode is by
   having a .inputrc when the program is first run.  There are times when
   I would like to be able to switch to vi-mode after bash is already
   running.  Why is the extra rc file (.inputrc) necessary, and why is
   that the only way to enter vi-mode?  

M-C-j toggles between the two modes.

Placing "set editing-mode vi" in your .inputrc file brings up line editing
in vi mode.

Typing C-x C-r re-reads your .inputrc file.

Brian

night@PAWL.RPI.EDU (Trip Martin KA2LIV night@pawl.rpi.edu) (11/13/89)

Thanks for the info regarding vi-mode.  I've made some changes so
that all the stuff that's done in the .inputrc can be done from the
shell as well.  I've added two flags to set: "+z" for vi-mode, and
"-s" for horizontal-scroll-mode.  For rebinding keys, I've added
the builtin "bind", which can handle both functions and macros (using
the "macro" keyword).  I've also changed vi-mode so that control
chars come out as ^X rather than C-X (vi does it this way, so I 
think bash should too in vi-mode).  Also, the builtin documentation
has been updated to reflect these changes.

I'd like to see these changes incorporated into the bash distribution.
If you'd like to use them, just send me a message, and I'll send you
the patches.
--
Trip Martin  KA2LIV       night@pawl.rpi.edu
Finite state machinist    night@uruguay.acm.rpi.edu

night@PAWL.RPI.EDU (Trip Martin KA2LIV night@pawl.rpi.edu) (11/13/89)

Here are the patches.  There are a couple of other patches I forgot
to mention.  Both affect reading stty settings for erase and kill
to include them in the keymaps.  The first allows it to work under
termio.  The second causes changes to be made in both emacs and vi
keymaps, so that a change in editing-mode won't affect those keys.

Trip Martin
--------------------------- cut here -----------------------------
*** flags.c	Sun Nov 12 23:36:37 1989
--- flags.c	Sun Nov 12 23:36:14 1989
***************
*** 96,101 ****
--- 96,109 ----
     This means !22 gets the 22nd line of history. */
  int history_expansion = 1;
  
+ /* Non-zero means emacs-editing mode in effect.  The variable is
+    already defined in readline/readline.c */
+ extern int rl_editing_mode;
+ 
+ /* Non-zero means that horizontal-scroll mode is in effect.  The
+    variable is already defined in readline/readline.c */
+ extern int horizontal_scroll_mode;
+ 
  /* **************************************************************** */
  /*								    */
  /*			The Flags ALIST.			    */
***************
*** 123,128 ****
--- 131,138 ----
    /* New flags that control non-standard things. */
    {"l", &lexical_scoping},
    {"i", &no_invisible_vars},
+   {"z", &rl_editing_mode},
+   {"s", &horizontal_scroll_mode},
  
    /* I want `h', but locate_commands_in_functions has it.  Great. */
    {"d", &hashing_disabled},
*** builtins.c	Sun Nov 12 23:38:32 1989
--- builtins.c	Sun Nov 12 23:46:09 1989
***************
*** 35,40 ****
--- 35,41 ----
  #include "trap.h"
  #include "flags.h"
  #include <readline/history.h>
+ #include <readline/readline.h>
  
  #ifdef JOB_CONTROL
  #include "jobs.h"
***************
*** 85,90 ****
--- 86,96 ----
  	word to be checked for alias substitution.  Alias returns true\n\
  	unless a NAME is given for which no alias has been defined" },
  
+   { "bind", bind_builtin, 1, "bind [ [[macro] key [predicate]] ... ]",
+       " Bind the key sequence KEY to PREDICATE, which can be either a\n\
+         function or a macro sequence.  If PREDICATE is to be a function\n\
+         and is either not present or is \"nil\", KEY is unbound" },
+ 
  #ifdef JOB_CONTROL
    { "bg", bg_builtin, 1, "bg [job_spec]",
        "	Place JOB_SPEC in the background, as if it had been started with\n\
***************
*** 264,270 ****
        "	Causes a function to exit with the return value specified by N.\n\
  	If N is omitted, the return status is that of the last command" },
  
!   { "set", set_builtin, 1, "set [-aefhkntuvx] [arg ...]",
        "	-a  Mark variables which are modified or created for export\n\
  	-e  Exit immediately if a command exits with a non-zero status\n\
  	-f  Disable file name generation (globbing)\n\
--- 270,276 ----
        "	Causes a function to exit with the return value specified by N.\n\
  	If N is omitted, the return status is that of the last command" },
  
!   { "set", set_builtin, 1, "set [-aefhknstuvxz] [arg ...]",
        "	-a  Mark variables which are modified or created for export\n\
  	-e  Exit immediately if a command exits with a non-zero status\n\
  	-f  Disable file name generation (globbing)\n\
***************
*** 282,287 ****
--- 288,296 ----
  	-d  Disable the hashing of commands that are looked up for execution.\n\
  	    Normally, commands are remembered in a hash table, and once\n\
  	    found, do not have to be looked up again\n\
+ 	-s  Enable horizontal-scroll-mode for command line editing\n\
+ 	-z  Enable emacs-mode for command line editing (disabling\n\
+             emacs-mode enables vi-mode)\n\
  	-o  Enable ! style history substitution.  This flag is on by\n\
  	    by default.\n\
  \n\
***************
*** 3293,3295 ****
--- 3302,3388 ----
  
  #endif  /* JOB_CONTROL */
  
+ /* We need the current keymap to pass to rl_set_key() */
+ extern Keymap keymap;
+ extern Function *rl_named_function();
+ 
+ bind_builtin (list)
+    WORD_LIST *list;
+ {
+ int keyseqlen, macro_len, bind_type;
+ char *key, *bind_name, keyseq[10], macro_keys[10];
+ Function *funcall;
+ 
+   while (list)
+     {
+       key = list->word->word;
+       list = list->next;
+ 
+       /* Is this a macro or function definition? */
+       if (strcmp (key, "macro") == 0)
+         {
+           bind_type = ISMACR;
+           if (list)
+             {
+               key = list->word->word;
+               list = list->next;
+             }
+           else
+             {
+               report_error ("bind: Missing macro definition");
+               return (EXECUTION_FAILURE);
+             }
+         }
+       else
+         bind_type = ISFUNC;
+ 
+       /* Get binding predicate */
+       if (list) 
+         {
+           bind_name = list->word->word;
+           list = list->next;
+         }
+       else
+         bind_name = (char *) NULL;
+ 
+       /* See if the key is to be unbound */
+       if (bind_type == ISFUNC && strcmp (bind_name, "nil") == 0)
+          bind_name = (char *) NULL;
+ 
+       /* See that the key given is valid */
+       if (rl_translate_keyseq (key, keyseq, &keyseqlen)) 
+         {
+           report_error ("bind: Invalid key %s",key);
+           return (EXECUTION_FAILURE);
+         }
+       else
+         keyseq[keyseqlen] = '\0';
+  
+       /* Make sure binding is valid */
+       if (bind_type == ISFUNC) 
+         {
+           /* Function key-binding -- make sure function actually exists */
+           if (bind_name && !(funcall = rl_named_function (bind_name)))
+             { 
+               report_error ("bind: Invalid function %s",bind_name);
+               return (EXECUTION_FAILURE);
+             }
+         }
+       else
+         if (bind_name &&
+                    !rl_translate_keyseq (bind_name, macro_keys, &macro_len))
+           macro_keys[macro_len] = '\0';
+         else
+           {
+             report_error ("bind: Invalid macro sequence: %s", bind_name);
+             return (EXECUTION_FAILURE);
+           }
+       
+       /* Everything checks out -- do key binding */
+       if (bind_type == ISFUNC)
+         rl_generic_bind (ISFUNC, keyseq, funcall, keymap);
+       else
+         rl_generic_bind (ISMACR, keyseq, macro_keys, keymap);
+     }
+   return (EXECUTION_SUCCESS);
+ }
*** readline.c	Sun Nov 12 23:52:29 1989
--- readline.c	Mon Nov 13 00:10:42 1989
***************
*** 1043,1053 ****
        int erase = ttybuff.sg_erase, kill = ttybuff.sg_kill;
  
        if (erase != -1 && keymap[erase].type == ISFUNC)
! 	keymap[erase].function = rl_rubout;
  
        if (kill != -1 && keymap[kill].type == ISFUNC)
! 	keymap[kill].function = rl_unix_line_discard;
      }
  
  #ifdef TIOCGLTC
    {
--- 1043,1059 ----
        int erase = ttybuff.sg_erase, kill = ttybuff.sg_kill;
  
        if (erase != -1 && keymap[erase].type == ISFUNC) 
!         {
!           emacs_standard_keymap[erase].function = rl_rubout;
!           vi_insertion_keymap[erase].function = rl_rubout;
!         }
  
        if (kill != -1 && keymap[kill].type == ISFUNC)
!         {
!           emacs_standard_keymap[kill].function = rl_unix_line_discard;
!           vi_insertion_keymap[kill].function = rl_unix_line_discard;
          }
+     }
  
  #ifdef TIOCGLTC
    {
***************
*** 1065,1070 ****
--- 1071,1098 ----
        }
    }
  #endif /* TIOCGLTC */
+ #else
+ #ifdef TCGETA
+   struct termio ttybuff;
+   int tty = fileno (rl_instream);
+ 
+   if (ioctl (tty, TCGETA, &ttybuff) != -1)
+     {
+     int erase = ttybuff.c_cc[VERASE], kill = ttybuff.c_cc[VKILL];
+ 
+       if (erase != -1 && keymap[erase].type == ISFUNC)
+         {
+           emacs_standard_keymap[erase].function = rl_rubout;
+           vi_insertion_keymap[erase].function = rl_rubout;
+         }
+ 
+       if (kill != -1 && keymap[kill].type == ISFUNC)
+         {
+           emacs_standard_keymap[kill].function = rl_unix_line_discard;
+           vi_insertion_keymap[kill].function = rl_unix_line_discard;
+         }
+     }
+ #endif /*  TCGETA */
  #endif /*  TIOCGETP */
  }
  
***************
*** 1311,1319 ****
--- 1339,1355 ----
  #endif
        else if (c < 32)
  	{
+           if (rl_editing_mode == emacs_mode) 
+             {
                line[out++] = 'C';
                line[out++] = '-';
                line[out++] = c + 64;
+             }
+           else
+             {
+               line[out++] = '^';
+               line[out++] = c + 64;
+             }
  	}
        else
  	line[out++] = c;