very nice command line tab completeion from Shawn Walker
authortaniwha <taniwha@d7cf8633-e32d-0410-b094-e92efae38249>
Fri, 20 Jul 2001 20:24:36 +0000 (20:24 +0000)
committertaniwha <taniwha@d7cf8633-e32d-0410-b094-e92efae38249>
Fri, 20 Jul 2001 20:24:36 +0000 (20:24 +0000)
<eviltypeguy@qeradiant.com> with my later modifications so that commands
are completed as much as possible.

git-svn-id: svn://svn.icculus.org/twilight/trunk/darkplaces@269 d7cf8633-e32d-0410-b094-e92efae38249

cmd.c
cmd.h
console.c
console.h
cvar.c
cvar.h
keys.c

diff --git a/cmd.c b/cmd.c
index ae32872..a834908 100644 (file)
--- a/cmd.c
+++ b/cmd.c
@@ -419,6 +419,45 @@ cmd_source_t       cmd_source;
 static cmd_function_t  *cmd_functions;         // possible commands to execute
 
 /*
+========
+Cmd_List
+
+       CmdList Added by EvilTypeGuy eviltypeguy@qeradiant.com
+       Thanks to Matthias "Maddes" Buecher, http://www.inside3d.com/qip/
+
+========
+*/
+void Cmd_List_f (void)
+{
+       cmd_function_t  *cmd;
+       char                    *partial;
+       int                             len;
+       int                             count;
+
+       if (Cmd_Argc() > 1) {
+               partial = Cmd_Argv (1);
+               len = strlen(partial);
+       } else {
+               partial = NULL;
+               len = 0;
+       }
+
+       count = 0;
+       for (cmd = cmd_functions; cmd; cmd = cmd->next) {
+               if (partial && strncmp(partial, cmd->name, len))
+                       continue;
+               Con_Printf ("%s\n", cmd->name);
+               count++;
+       }
+
+       Con_Printf ("%i Command%s", count, (count > 1) ? "s" : "");
+       if (partial)
+               Con_Printf(" beginning with \"%s\"", partial);
+
+       Con_Printf ("\n\n");
+}
+
+/*
 ============
 Cmd_Init
 ============
@@ -434,6 +473,9 @@ void Cmd_Init (void)
        Cmd_AddCommand ("alias",Cmd_Alias_f);
        Cmd_AddCommand ("cmd", Cmd_ForwardToServer);
        Cmd_AddCommand ("wait", Cmd_Wait_f);
+       Cmd_AddCommand ("cmdlist", Cmd_List_f);         // Added/Modified by EvilTypeGuy eviltypeguy@qeradiant.com
+       Cmd_AddCommand ("cvarlist", Cvar_List_f);       // 2000-01-09 CmdList, CvarList commands
+                                                                                               // By Matthias "Maddes" Buecher
 }
 
 /*
@@ -463,7 +505,7 @@ char        *Cmd_Argv (int arg)
 Cmd_Args
 ============
 */
-char           *Cmd_Args (void)
+char   *Cmd_Args (void)
 {
        return cmd_args;
 }
@@ -594,14 +636,161 @@ char *Cmd_CompleteCommand (char *partial)
                return NULL;
                
 // check functions
-       for (cmd=cmd_functions ; cmd ; cmd=cmd->next)
-               if (!strncmp (partial,cmd->name, len))
+       for (cmd = cmd_functions; cmd; cmd = cmd->next)
+               if (!strncmp(partial, cmd->name, len))
                        return cmd->name;
 
        return NULL;
 }
 
 /*
+       Cmd_CompleteCountPossible
+
+       New function for tab-completion system
+       Added by EvilTypeGuy
+       Thanks to Fett erich@heintz.com
+       Thanks to taniwha
+
+*/
+int
+Cmd_CompleteCountPossible (char *partial)
+{
+       cmd_function_t  *cmd;
+       int                             len;
+       int                             h;
+       
+       h = 0;
+       len = strlen(partial);
+       
+       if (!len)
+               return 0;
+       
+       // Loop through the command list and count all partial matches
+       for (cmd = cmd_functions; cmd; cmd = cmd->next)
+               if (!strncasecmp(partial, cmd->name, len))
+                       h++;
+
+       return h;
+}
+
+/*
+       Cmd_CompleteBuildList
+
+       New function for tab-completion system
+       Added by EvilTypeGuy
+       Thanks to Fett erich@heintz.com
+       Thanks to taniwha
+
+*/
+char   **
+Cmd_CompleteBuildList (char *partial)
+{
+       cmd_function_t  *cmd;
+       int                             len = 0;
+       int                             bpos = 0;
+       int                             sizeofbuf = (Cmd_CompleteCountPossible (partial) + 1) * sizeof (char *);
+       char                    **buf;
+
+       len = strlen(partial);
+       buf = malloc(sizeofbuf + sizeof (char *));
+       // Loop through the alias list and print all matches
+       for (cmd = cmd_functions; cmd; cmd = cmd->next)
+               if (!strncasecmp(partial, cmd->name, len))
+                       buf[bpos++] = cmd->name;
+
+       buf[bpos] = NULL;
+       return buf;
+}
+
+/*
+       Cmd_CompleteAlias
+
+       New function for tab-completion system
+       Added by EvilTypeGuy
+       Thanks to Fett erich@heintz.com
+       Thanks to taniwha
+
+*/
+char
+*Cmd_CompleteAlias (char * partial)
+{
+       cmdalias_t      *alias;
+       int                     len;
+
+       len = strlen(partial);
+
+       if (!len)
+               return NULL;
+
+       // Check functions
+       for (alias = cmd_alias; alias; alias = alias->next)
+               if (!strncasecmp(partial, alias->name, len))
+                       return alias->name;
+
+       return NULL;
+}
+
+/*
+       Cmd_CompleteAliasCountPossible
+
+       New function for tab-completion system
+       Added by EvilTypeGuy
+       Thanks to Fett erich@heintz.com
+       Thanks to taniwha
+
+*/
+int
+Cmd_CompleteAliasCountPossible (char *partial)
+{
+       cmdalias_t      *alias;
+       int                     len;
+       int                     h;
+
+       h = 0;
+
+       len = strlen(partial);
+
+       if (!len)
+               return 0;
+
+       // Loop through the command list and count all partial matches
+       for (alias = cmd_alias; alias; alias = alias->next)
+               if (!strncasecmp(partial, alias->name, len))
+                       h++;
+
+       return h;
+}
+
+/*
+       Cmd_CompleteAliasBuildList
+
+       New function for tab-completion system
+       Added by EvilTypeGuy
+       Thanks to Fett erich@heintz.com
+       Thanks to taniwha
+
+*/
+char   **
+Cmd_CompleteAliasBuildList (char *partial)
+{
+       cmdalias_t      *alias;
+       int                     len = 0;
+       int                     bpos = 0;
+       int                     sizeofbuf = (Cmd_CompleteAliasCountPossible (partial) + 1) * sizeof (char *);
+       char            **buf;
+
+       len = strlen(partial);
+       buf = malloc(sizeofbuf + sizeof (char *));
+       // Loop through the alias list and print all matches
+       for (alias = cmd_alias; alias; alias = alias->next)
+               if (!strncasecmp(partial, alias->name, len))
+                       buf[bpos++] = alias->name;
+
+       buf[bpos] = NULL;
+       return buf;
+}
+
+/*
 ============
 Cmd_ExecuteString
 
@@ -701,3 +890,4 @@ int Cmd_CheckParm (char *parm)
                        
        return 0;
 }
+
diff --git a/cmd.h b/cmd.h
index da1daa6..5583b32 100644 (file)
--- a/cmd.h
+++ b/cmd.h
@@ -91,6 +91,14 @@ char         *Cmd_CompleteCommand (char *partial);
 // attempts to match a partial command for automatic command line completion
 // returns NULL if nothing fits
 
+int            Cmd_CompleteAliasCountPossible (char *partial);
+char   **Cmd_CompleteAliasBuildList (char *partial);
+int            Cmd_CompleteCountPossible (char *partial);
+char   **Cmd_CompleteBuildList (char *partial);
+char   *Cmd_CompleteAlias (char *partial);
+// Enhanced console completion by Fett erich@heintz.com
+// Added by EvilTypeGuy eviltypeguy@qeradiant.com
+
 int            Cmd_Argc (void);
 char   *Cmd_Argv (int arg);
 char   *Cmd_Args (void);
index 2c8939b..a034a29 100644 (file)
--- a/console.c
+++ b/console.c
@@ -45,28 +45,29 @@ int                 con_totallines;         // total lines in console scrollback
 int                    con_backscroll;         // lines up from bottom to display
 int                    con_current;            // where next message will be printed
 int                    con_x;                          // offset in current line for next print
-char           *con_text=0;
+char           *con_text = 0;
 
-cvar_t         con_notifytime = {"con_notifytime","3"};                //seconds
+cvar_t         con_notifytime = {"con_notifytime","3"};        //seconds
 cvar_t         logfile = {"logfile","0"};
 
 #define        NUM_CON_TIMES 4
 float          con_times[NUM_CON_TIMES];       // realtime time the line was generated
-                                                               // for transparent notify lines
+                                               // for transparent notify lines
 
 int                    con_vislines;
 
 qboolean       con_debuglog;
 
-#define                MAXCMDLINE      256
+#define        MAXCMDLINE      256
 extern char    key_lines[32][MAXCMDLINE];
 extern int             edit_line;
 extern int             key_linepos;
+extern int             key_insert;
                
 
 qboolean       con_initialized;
 
-int                    con_notifylines;                // scan lines to clear for notify lines
+int            con_notifylines;                // scan lines to clear for notify lines
 
 extern void M_Menu_Main_f (void);
 
@@ -487,39 +488,53 @@ DRAWING
 Con_DrawInput
 
 The input line scrolls horizontally if typing goes beyond the right edge
+
+Modified by EvilTypeGuy eviltypeguy@qeradiant.com
 ================
 */
 void Con_DrawInput (void)
 {
        int             y;
        char    *text;
+       char    editlinecopy[256];
 
        if (key_dest != key_console && !con_forcedup)
                return;         // don't draw anything
 
-       text = key_lines[edit_line];
+       text = strcpy(editlinecopy, key_lines[edit_line]);
+       y = strlen(text);
+       
+       // Advanced Console Editing by Radix radix@planetquake.com
+       // Added/Modified by EvilTypeGuy eviltypeguy@qeradiant.com
+       // use strlen of edit_line instead of key_linepos to allow editing
+       // of early characters w/o erasing
+
+       // add the cursor frame
+       if ((int)(realtime*con_cursorspeed) & 1)                // cursor is visible
+               text[key_linepos] = 11 + 130 * key_insert;      // either solid or triangle facing right
        
-// add the cursor frame
-       text[key_linepos] = 10+((int)(realtime*con_cursorspeed)&1);
+       text[key_linepos + 1] = 0; // LordHavoc: null terminate, rather than padding with spaces
+       // text[key_linepos] = 10 + ((int)(realtime*con_cursorspeed) & 1);
        
-       text[key_linepos+1] = 0; // LordHavoc: null terminate, rather than padding with spaces
-// fill out remainder with spaces
-//     for (i=key_linepos+1 ; i< con_linewidth ; i++)
-//             text[i] = ' ';
+
+       // fill out remainder with spaces
+       //      for (i=key_linepos+1 ; i< con_linewidth ; i++)
+       //              text[i] = ' ';
                
-//     prestep if horizontally scrolling
+       //      prestep if horizontally scrolling
        if (key_linepos >= con_linewidth)
                text += 1 + key_linepos - con_linewidth;
                
-// draw it
-       y = con_vislines-16;
+       // draw it
+       y = con_vislines - 16;
+
+       //      for (i=0 ; i<con_linewidth ; i++)
+       //              Draw_Character ( (i+1)<<3, con_vislines - 16, text[i]);
 
-//     for (i=0 ; i<con_linewidth ; i++)
-//             Draw_Character ( (i+1)<<3, con_vislines - 16, text[i]);
        // LordHavoc: speedup
        Draw_String(8, con_vislines - 16, text, con_linewidth);
 
-// remove cursor
+       // remove cursor
        key_lines[edit_line][key_linepos] = 0;
 }
 
@@ -644,3 +659,146 @@ void Con_DrawConsole (int lines, qboolean drawinput)
        if (drawinput)
                Con_DrawInput ();
 }
+
+/*
+       Con_DisplayList
+
+       New function for tab-completion system
+       Added by EvilTypeGuy
+       MEGA Thanks to Taniwha
+
+*/
+void
+Con_DisplayList(char **list)
+{
+       int     i = 0;
+       int     pos = 0;
+       int     len = 0;
+       int     maxlen = 0;
+       int     width = (con_linewidth - 4);
+       char    **walk = list;
+
+       while (*walk) {
+               len = strlen(*walk);
+               if (len > maxlen)
+                       maxlen = len;
+               walk++;
+       }
+       maxlen += 1;
+
+       while (*list) {
+               len = strlen(*list);
+               if (pos + maxlen >= width) {
+                       Con_Printf("\n");
+                       pos = 0;
+               }
+
+               Con_Printf("%s", *list);
+               for (i = 0; i < (maxlen - len); i++)
+                       Con_Printf(" ");
+
+               pos += maxlen;
+               list++;
+       }
+
+       if (pos)
+               Con_Printf("\n\n");
+}
+
+/*
+       Con_CompleteCommandLine
+
+       New function for tab-completion system
+       Added by EvilTypeGuy
+       Thanks to Fett erich@heintz.com
+       Thanks to taniwha
+
+*/
+void
+Con_CompleteCommandLine (void)
+{
+       char    *cmd = "";
+       char    *s;
+       int             c, v, a, i;
+       int             cmd_len;
+       char    **list[3] = {0, 0, 0};
+
+       s = key_lines[edit_line] + 1;
+       // Count number of possible matches
+       c = Cmd_CompleteCountPossible(s);
+       v = Cvar_CompleteCountPossible(s);
+       a = Cmd_CompleteAliasCountPossible(s);
+       
+       if (!(c + v + a))       // No possible matches
+               return;
+       
+       if (c + v + a == 1) {
+               if (c)
+                       list[0] = Cmd_CompleteBuildList(s);
+               else if (v)
+                       list[0] = Cvar_CompleteBuildList(s);
+               else
+                       list[0] = Cmd_CompleteAliasBuildList(s);
+               cmd = *list[0];
+               cmd_len = strlen (cmd);
+       } else {
+               if (c)
+                       cmd = *(list[0] = Cmd_CompleteBuildList(s));
+               if (v)
+                       cmd = *(list[1] = Cvar_CompleteBuildList(s));
+               if (a)
+                       cmd = *(list[2] = Cmd_CompleteAliasBuildList(s));
+
+               cmd_len = strlen (s);
+               do {
+                       for (i = 0; i < 3; i++) {
+                               char ch = cmd[cmd_len];
+                               char **l = list[i];
+                               if (l) {
+                                       while (*l && (*l)[cmd_len] == ch)
+                                               l++;
+                                       if (*l)
+                                               break;
+                               }
+                       }
+                       if (i == 3)
+                               cmd_len++;
+               } while (i == 3);
+               // 'quakebar'
+               Con_Printf("\n\35");
+               for (i = 0; i < con_linewidth - 4; i++)
+                       Con_Printf("\36");
+               Con_Printf("\37\n");
+
+               // Print Possible Commands
+               if (c) {
+                       Con_Printf("%i possible command%s\n", c, (c > 1) ? "s: " : ":");
+                       Con_DisplayList(list[0]);
+               }
+               
+               if (v) {
+                       Con_Printf("%i possible variable%s\n", v, (v > 1) ? "s: " : ":");
+                       Con_DisplayList(list[1]);
+               }
+               
+               if (a) {
+                       Con_Printf("%i possible aliases%s\n", a, (a > 1) ? "s: " : ":");
+                       Con_DisplayList(list[2]);
+               }
+               return;
+       }
+       
+       if (cmd) {
+               strncpy(key_lines[edit_line] + 2, cmd, cmd_len);
+               key_linepos = cmd_len + 2;
+               if (c + v + a == 1) {
+                       key_lines[edit_line][key_linepos] = ' ';
+                       key_linepos++;
+               }
+               key_lines[edit_line][key_linepos] = 0;
+       }
+       for (i = 0; i < 3; i++)
+               if (list[i])
+                       free (list[i]);
+}
+
index 5827312..1ba74e1 100644 (file)
--- a/console.h
+++ b/console.h
@@ -41,3 +41,14 @@ void Con_Clear_f (void);
 void Con_DrawNotify (void);
 void Con_ClearNotify (void);
 void Con_ToggleConsole_f (void);
+
+// wrapper function to attempt to either complete the command line
+// or to list possible matches grouped by type
+// (i.e. will display possible variables, aliases, commands
+// that match what they've typed so far)
+void Con_CompleteCommandLine(void);
+
+// Generic libs/util/console.c function to display a list
+// formatted in columns on the console
+void Con_DisplayList(char **list);
+
diff --git a/cvar.c b/cvar.c
index 0f8ccd4..318adc4 100644 (file)
--- a/cvar.c
+++ b/cvar.c
@@ -97,6 +97,64 @@ char *Cvar_CompleteVariable (char *partial)
 
 
 /*
+       CVar_CompleteCountPossible
+
+       New function for tab-completion system
+       Added by EvilTypeGuy
+       Thanks to Fett erich@heintz.com
+
+*/
+int
+Cvar_CompleteCountPossible (char *partial)
+{
+       cvar_t  *cvar;
+       int             len;
+       int             h;
+       
+       h = 0;
+       len = strlen(partial);
+       
+       if (!len)
+               return  0;
+       
+       // Loop through the cvars and count all possible matches
+       for (cvar = cvar_vars; cvar; cvar = cvar->next)
+               if (!strncasecmp(partial, cvar->name, len))
+                       h++;
+       
+       return h;
+}
+
+/*
+       CVar_CompleteBuildList
+
+       New function for tab-completion system
+       Added by EvilTypeGuy
+       Thanks to Fett erich@heintz.com
+       Thanks to taniwha
+
+*/
+char   **
+Cvar_CompleteBuildList (char *partial)
+{
+       cvar_t  *cvar;
+       int             len = 0;
+       int             bpos = 0;
+       int             sizeofbuf = (Cvar_CompleteCountPossible (partial) + 1) * sizeof (char *);
+       char    **buf;
+
+       len = strlen(partial);
+       buf = malloc(sizeofbuf + sizeof (char *));
+       // Loop through the alias list and print all matches
+       for (cvar = cvar_vars; cvar; cvar = cvar->next)
+               if (!strncasecmp(partial, cvar->name, len))
+                       buf[bpos++] = cvar->name;
+
+       buf[bpos] = NULL;
+       return buf;
+}      
+
+/*
 ============
 Cvar_Set
 ============
@@ -223,3 +281,41 @@ void Cvar_WriteVariables (QFile *f)
                        Qprintf (f, "%s \"%s\"\n", var->name, var->string);
 }
 
+
+// Added by EvilTypeGuy eviltypeguy@qeradiant.com
+// 2000-01-09 CvarList command By Matthias "Maddes" Buecher, http://www.inside3d.com/qip/
+/*
+=========
+Cvar_List
+=========
+*/
+void Cvar_List_f (void)
+{
+       cvar_t  *cvar;
+       char    *partial;
+       int             len;
+       int             count;
+
+       if (Cmd_Argc() > 1) {
+               partial = Cmd_Argv (1);
+               len = strlen(partial);
+       } else {
+               partial = NULL;
+               len = 0;
+       }
+
+       count = 0;
+       for (cvar = cvar_vars; cvar; cvar = cvar->next) {
+               if (partial && strncmp (partial,cvar->name,len))
+                       continue;
+
+               Con_Printf ("%s is \"%s\"\n", cvar->name, cvar->string);
+               count++;
+       }
+
+       Con_Printf ("%i cvar(s)", count);
+       if (partial)
+               Con_Printf (" beginning with \"%s\"", partial);
+       Con_Printf ("\n");
+}
+// 2000-01-09 CvarList command by Maddes
diff --git a/cvar.h b/cvar.h
index 6aa1ad1..1c73c39 100644 (file)
--- a/cvar.h
+++ b/cvar.h
@@ -95,3 +95,16 @@ void         Cvar_WriteVariables (QFile *f);
 cvar_t *Cvar_FindVar (char *var_name);
 
 extern cvar_t  *cvar_vars;
+
+int            Cvar_CompleteCountPossible (char *partial);
+char   **Cvar_CompleteBuildList (char *partial);
+// Added by EvilTypeGuy - functions for tab completion system
+// Thanks to Fett erich@heintz.com
+// Thanks to taniwha
+
+void   Cvar_List_f (void);
+// Prints a list of Cvars including a count of them to the user console
+// Referenced in cmd.c in Cmd_Init hence it's inclusion here
+// Added by EvilTypeGuy eviltypeguy@qeradiant.com
+// Thanks to Matthias "Maddes" Buecher, http://www.inside3d.com/qip/
+
diff --git a/keys.c b/keys.c
index 1929b68..a3d1f15 100644 (file)
--- a/keys.c
+++ b/keys.c
@@ -29,11 +29,12 @@ key up events are sent even if in console mode
 #define                MAXCMDLINE      256
 char   key_lines[32][MAXCMDLINE];
 int            key_linepos;
-int            shift_down=false;
+int            shift_down = false;
 int            key_lastpress;
+int            key_insert;     // insert key toggle (for editing)
 
-int            edit_line=0;
-int            history_line=0;
+int            edit_line = 0;
+int            history_line = 0;
 
 keydest_t      key_dest;
 
@@ -158,8 +159,6 @@ Interactive line editing and console scrollback
 */
 void Key_Console (int key)
 {
-       char    *cmd;
-       
        if (key == K_ENTER)
        {
                Cbuf_AddText (key_lines[edit_line]+1);  // skip the >
@@ -168,36 +167,79 @@ void Key_Console (int key)
                edit_line = (edit_line + 1) & 31;
                history_line = edit_line;
                key_lines[edit_line][0] = ']';
+               key_lines[edit_line][1] = 0;    // EvilTypeGuy: null terminate
                key_linepos = 1;
                if (cls.state == ca_disconnected)
                        SCR_UpdateScreen ();    // force an update, because the command
-                                                                       // may take some time
+                                               // may take some time
                return;
        }
 
        if (key == K_TAB)
-       {       // command completion
-               cmd = Cmd_CompleteCommand (key_lines[edit_line]+1);
-               if (!cmd)
-                       cmd = Cvar_CompleteVariable (key_lines[edit_line]+1);
-               if (cmd)
-               {
-                       strcpy (key_lines[edit_line]+1, cmd);
-                       key_linepos = strlen(cmd)+1;
-                       key_lines[edit_line][key_linepos] = ' ';
-                       key_linepos++;
-                       key_lines[edit_line][key_linepos] = 0;
-                       return;
-               }
+       {
+               // Enhanced command completion
+               // by EvilTypeGuy eviltypeguy@qeradiant.com
+               // Thanks to Fett, Taniwha
+               Con_CompleteCommandLine();
        }
        
-       if (key == K_BACKSPACE || key == K_LEFTARROW)
+       // Advanced Console Editing by Radix radix@planetquake.com
+       // Added/Modified by EvilTypeGuy eviltypeguy@qeradiant.com
+
+       // left arrow will just move left one without erasing, backspace will
+       // actually erase charcter
+       if (key == K_LEFTARROW)
+       {
+               if (key_linepos > 1)
+                       key_linepos--;
+               return;
+       }
+
+       if (key == K_BACKSPACE) // delete char before cursor
        {
                if (key_linepos > 1)
+               {
+                       strcpy(key_lines[edit_line] + key_linepos - 1, key_lines[edit_line] + key_linepos);
                        key_linepos--;
+               }
+               return;
+       }
+
+       if (key == K_DEL)               // delete char on cursor
+       {
+               if (key_linepos < strlen(key_lines[edit_line]))
+                       strcpy(key_lines[edit_line] + key_linepos, key_lines[edit_line] + key_linepos + 1);
+               return;
+       }
+
+
+       // if we're at the end, get one character from previous line,
+       // otherwise just go right one
+       if (key == K_RIGHTARROW)
+       {
+               if (strlen(key_lines[edit_line]) == key_linepos)
+               {
+                       if (strlen(key_lines[(edit_line + 31) & 31]) <= key_linepos)
+                               return; // no character to get
+
+                       key_lines[edit_line][key_linepos] = key_lines[(edit_line + 31) & 31][key_linepos];
+                       key_linepos++;
+                       key_lines[edit_line][key_linepos] = 0;
+               }
+               else
+                       key_linepos++;
+
+               return;
+       }
+
+       if (key == K_INS) // toggle insert mode
+       {       
+               key_insert ^= 1;
                return;
        }
 
+       // End Advanced Console Editing
+
        if (key == K_UPARROW)
        {
                do
@@ -265,13 +307,32 @@ void Key_Console (int key)
        if (key < 32 || key > 127)
                return; // non printable
                
+
+
        if (key_linepos < MAXCMDLINE-1)
        {
+               int i;
+
+               if (key_insert) // check insert mode
+               {
+                       // can't do strcpy to move string to right
+                       i = strlen(key_lines[edit_line]) - 1;
+
+                       if (i == 254)
+                               i--;
+
+                       for (; i >= key_linepos; i--)
+                               key_lines[edit_line][i + 1] = key_lines[edit_line][i];
+               }
+
+               // only null terminate if at the end
+               i = key_lines[edit_line][key_linepos];
                key_lines[edit_line][key_linepos] = key;
                key_linepos++;
-               key_lines[edit_line][key_linepos] = 0;
-       }
 
+               if (!i)
+                       key_lines[edit_line][key_linepos] = 0;
+       }
 }
 
 //============================================================================
@@ -542,6 +603,8 @@ void Key_Init (void)
        consolekeys[K_UPARROW] = true;
        consolekeys[K_DOWNARROW] = true;
        consolekeys[K_BACKSPACE] = true;
+       consolekeys[K_DEL] = true;
+       consolekeys[K_INS] = true;
        consolekeys[K_PGUP] = true;
        consolekeys[K_PGDN] = true;
        consolekeys[K_SHIFT] = true;