From cb2a285f50a6a0bf54a9d7e65579cb6edcda008b Mon Sep 17 00:00:00 2001
From: Jose Antonio Ortega Ruiz <jao@gnu.org>
Date: Wed, 6 Jun 2001 22:49:25 +0000
Subject: command history and tab completion added

---
 NEWS                           |  15 +++
 mixgtk/mixgtk.glade            |  33 ++---
 mixgtk/mixgtk_cmd_dispatcher.c | 274 +++++++++++++++++------------------------
 3 files changed, 144 insertions(+), 178 deletions(-)

diff --git a/NEWS b/NEWS
index 2785fb6..775e4e5 100644
--- a/NEWS
+++ b/NEWS
@@ -17,13 +17,28 @@ Please send mdk bug reports to bug-mdk@gnu.org.
    external programs used can be configured using the menu entry
    Settings->External programs.
 
+** The commands 'edit' and 'compile' can be now executed without
+   argument (both in mixvm and gmixvm). When no argument is given, the
+   MIXAL source file corresponding to the currently loaded MIX program
+   is edited/compiled.
+
 ** Bug in CON fixed : 'CON wexpr' didn't compile correctly unless wexpr
    represented a valid instruction; now, wexpr can evaluate to an
    arbitrary value (Vasilij Ozmetelenko).
 
+** The completion key for the gmixvm command prompt is now TAB
+   (instead of RETURN).
+   
+** The gmixvm command prompt maintains now a history of previously
+   typed commands, which can be visited using the arrow keys (UP for
+   previous commands, DOWN for next).
+
 ** When a file is reloaded by the virtual machine (both in mixvm and
    gmixvm), the currently set breakpoints are conserved.
 
+** When compiling a source file which is not in the current directory, the
+   correct path is now stored in the compiled file.
+
 ---------------------------------------------------------------------------
 * Version 0.3.2 (10/04/01)
 
diff --git a/mixgtk/mixgtk.glade b/mixgtk/mixgtk.glade
index a0dcfcf..5a74485 100644
--- a/mixgtk/mixgtk.glade
+++ b/mixgtk/mixgtk.glade
@@ -1220,7 +1220,7 @@
 	    <widget>
 	      <class>GtkScrolledWindow</class>
 	      <name>mixlog_scrolledwindow</name>
-	      <hscrollbar_policy>GTK_POLICY_NEVER</hscrollbar_policy>
+	      <hscrollbar_policy>GTK_POLICY_AUTOMATIC</hscrollbar_policy>
 	      <vscrollbar_policy>GTK_POLICY_ALWAYS</vscrollbar_policy>
 	      <hupdate_policy>GTK_UPDATE_CONTINUOUS</hupdate_policy>
 	      <vupdate_policy>GTK_UPDATE_CONTINUOUS</vupdate_policy>
@@ -1245,9 +1245,10 @@
 	      <can_focus>True</can_focus>
 	      <has_focus>True</has_focus>
 	      <signal>
-		<name>activate</name>
-		<handler>on_mixvm_cmd_entry_activate</handler>
-		<last_modification_time>Thu, 22 Feb 2001 23:26:28 GMT</last_modification_time>
+		<name>key_press_event</name>
+		<handler>on_command_prompt_key_press_event</handler>
+		<after>True</after>
+		<last_modification_time>Wed, 06 Jun 2001 06:46:05 GMT</last_modification_time>
 	      </signal>
 	      <editable>True</editable>
 	      <text_visible>True</text_visible>
@@ -2519,7 +2520,7 @@
 <widget>
   <class>GtkDialog</class>
   <name>external_dialog</name>
-  <width>235</width>
+  <width>285</width>
   <height>210</height>
   <visible>False</visible>
   <signal>
@@ -2636,23 +2637,23 @@
 	  <name>editor_entry</name>
 	  <x>48</x>
 	  <y>40</y>
-	  <width>160</width>
+	  <width>220</width>
 	  <height>24</height>
 	  <can_focus>True</can_focus>
 	  <editable>True</editable>
 	  <text_visible>True</text_visible>
 	  <text_max_length>0</text_max_length>
-	  <text>vi %s</text>
+	  <text>xterm -e vi %s</text>
 	</widget>
 
 	<widget>
 	  <class>GtkLabel</class>
 	  <name>label234</name>
-	  <x>16</x>
+	  <x>3</x>
 	  <y>16</y>
-	  <width>176</width>
+	  <width>223</width>
 	  <height>16</height>
-	  <label>Editor command (e.g vi %s)</label>
+	  <label>Editor command (e.g xterm -e vi %s)</label>
 	  <justify>GTK_JUSTIFY_LEFT</justify>
 	  <wrap>False</wrap>
 	  <xalign>0.5</xalign>
@@ -2676,23 +2677,23 @@
 	  <name>mixasm_entry</name>
 	  <x>48</x>
 	  <y>40</y>
-	  <width>158</width>
+	  <width>220</width>
 	  <height>22</height>
 	  <can_focus>True</can_focus>
 	  <editable>True</editable>
 	  <text_visible>True</text_visible>
 	  <text_max_length>0</text_max_length>
-	  <text>mixasm -g</text>
+	  <text>mixasm -g %s</text>
 	</widget>
 
 	<widget>
 	  <class>GtkLabel</class>
 	  <name>label235</name>
-	  <x>11</x>
-	  <y>8</y>
-	  <width>168</width>
+	  <x>0</x>
+	  <y>16</y>
+	  <width>278</width>
 	  <height>16</height>
-	  <label>MIX sssembler command</label>
+	  <label>MIX sssembler command (e.g. mixasm -g %s)</label>
 	  <justify>GTK_JUSTIFY_LEFT</justify>
 	  <wrap>False</wrap>
 	  <xalign>0.5</xalign>
diff --git a/mixgtk/mixgtk_cmd_dispatcher.c b/mixgtk/mixgtk_cmd_dispatcher.c
index bb1d4db..5076727 100644
--- a/mixgtk/mixgtk_cmd_dispatcher.c
+++ b/mixgtk/mixgtk_cmd_dispatcher.c
@@ -29,6 +29,13 @@
 #include <fcntl.h>
 #include <errno.h>
 
+#include <mixlib/mix.h>
+
+#ifdef HAVE_LIBHISTORY
+#  include <readline/history.h>
+#endif
+
+#include <gdk/gdkkeysyms.h>
 #include <mixlib/mix_vm_command.h>
 #include "mixgtk_mixvm.h"
 #include "mixgtk_mixal.h"
@@ -51,21 +58,18 @@ typedef struct mixgtk_dispatch_
 
 static struct mixgtk_dispatch_ dis_data_ = {NULL};
 
-/* local commands stuff */
-static const gchar *EDITOR_ = NULL;
-static const gchar *MIXASM_ = NULL;
-static const gchar *EDITOR_KEY_ = "Editor";
-static const gchar *MIXASM_KEY_ = "Mixasm";
-
-typedef gboolean (*local_handler_t) (mixgtk_dispatch_data_t *,
-				     const gchar *);
-
 static void
 log_command_ (mixgtk_dispatch_data_t *dis, const gchar *cmd)
 {
   gtk_text_insert (GTK_TEXT (dis->log), NULL, NULL, NULL,"MIX> ", -1);
   gtk_text_insert (GTK_TEXT (dis->log), NULL, NULL, NULL, cmd, -1);
   gtk_text_insert (GTK_TEXT (dis->log), NULL, NULL, NULL, "\n", -1);
+
+#ifdef HAVE_LIBHISTORY
+  add_history ((char *)cmd);
+/*  history_search ((char *)cmd, 0); */
+  history_set_pos (history_base + history_length - 1);
+#endif
 }
 
 static void
@@ -85,90 +89,6 @@ flush_log_ (mixgtk_dispatch_data_t *dis)
     }
 }
 
-static gboolean
-exec_ (mixgtk_dispatch_data_t *dis, const gchar *cmd, const gchar *arg)
-{
-  gchar *fullcmd = NULL;
-  gboolean r = FALSE;
-  fullcmd = g_strdup_printf (cmd, arg);
-  r = !system (fullcmd);
-  flush_log_ (dis);
-  g_free (fullcmd);
-  return r;
-}
-
-static const gchar *
-get_src_file_path_ (mixgtk_dispatch_data_t *dis)
-{
-  static gchar *PATH = NULL;
-  
-  const mix_vm_t *vm = mix_vm_cmd_dispatcher_get_vm (dis->dispatcher);
-  const mix_src_file_t *f  = mix_vm_get_src_file (vm);
-  
-  if (PATH)
-    {
-      g_free (PATH);
-      PATH = NULL;
-    }
-    
-  if (f)
-    PATH = mix_file_complete_name (mix_src_file_get_path (f), MIX_SRC_DEFEXT);
-      
-  return PATH;
-}
-
-static gboolean
-edit_handler_ (mixgtk_dispatch_data_t *dis, const gchar *arg)
-{
-  if (!arg) arg = get_src_file_path_ (dis);
-  if (!arg) return FALSE;
-  return exec_ (dis, EDITOR_, arg);
-}
-
-static gboolean
-compile_handler_ (mixgtk_dispatch_data_t *dis, const gchar *arg)
-{
-  if (!arg) arg = get_src_file_path_ (dis);
-  if (!arg) return FALSE;
-  return exec_ (dis, MIXASM_, arg);
-}
-
-static const gchar* local_cmds_[] = {
-  "edit", "compile"
-};
-
-static const local_handler_t handlers_[] = {
-  edit_handler_, compile_handler_
-};
-
-#define LOCAL_NO_ (sizeof (local_cmds_) / sizeof (local_cmds_[0]))
-
-static gboolean
-dispatch_local_command_ (mixgtk_dispatch_data_t *dis, const gchar *cmd)
-{
-  int k = 0;
-  
-  g_return_val_if_fail (dis != NULL, FALSE);
-  g_return_val_if_fail (cmd != NULL, FALSE);
-
-  for (k = 0; k < LOCAL_NO_; ++k)
-    {
-      if (!strncmp (local_cmds_[k], cmd, strlen (local_cmds_[k])))
-	{
-	  int j = 0;
-	  const gchar *arg = NULL;
-	  while (cmd[j] && !isspace (cmd[j])) ++j;
-	  if (cmd[j]) arg = cmd + j;
-	  log_command_ (dis, cmd);
-	  handlers_[k](dis, arg);
-	  return TRUE;
-	}
-    }
-  
-  return FALSE;
-}
-	  
-
 /* completions */
 static void
 init_completions_ (void)
@@ -179,37 +99,9 @@ init_completions_ (void)
   dis_data_.completions = g_completion_new (NULL);
   for (k = 0; k < MIX_CMD_INVALID; ++k)
     cmds = g_list_append (cmds, (gpointer) mix_vm_command_to_string (k));
-  for (k = 0; k < sizeof (local_cmds_) / sizeof (local_cmds_[0]); ++k)
-    cmds = g_list_append (cmds, (gpointer)local_cmds_[k]);
   g_completion_add_items (dis_data_.completions, cmds);
 }
 
-/* global hooks for the command dispatcher 
-static void
-global_pre_hook_ (mix_vm_cmd_dispatcher_t *dis,
-		  mix_vm_command_t cmd, const gchar *arg, gpointer data)
-{
-  if (cmd < MIX_CMD_INVALID)
-    {
-      gtk_text_insert (GTK_TEXT (dis_data_.log), NULL, NULL, NULL,
-		       "MIX> ", -1);
-      gtk_text_insert (GTK_TEXT (dis_data_.log), NULL, NULL, NULL,
-		       mix_vm_command_to_string (cmd), -1);
-      gtk_text_insert (GTK_TEXT (dis_data_.log), NULL, NULL, NULL,
-		       " ", -1);
-      gtk_text_insert (GTK_TEXT (dis_data_.log), NULL, NULL, NULL,
-		       arg, -1);
-      gtk_text_insert (GTK_TEXT (dis_data_.log), NULL, NULL, NULL,
-		       "\n", -1);
-    }
-  else
-    {
-      gtk_text_insert (GTK_TEXT (dis_data_.log), NULL, NULL, NULL,
-		       _("\n*** Invalid command ***\n"), -1);
-    }
-}
-*/
-
 static void
 global_post_hook_ (mix_vm_cmd_dispatcher_t *dis,
 		   mix_vm_command_t cmd, const gchar *arg, gpointer data)
@@ -309,19 +201,44 @@ install_hooks_ (void)
 }
 
 /* configuration stuff */
+static const gchar *EDITOR_KEY_ = "Editor";
+static const gchar *MIXASM_KEY_ = "Mixasm";
+static const gchar *HISTORY_FILE_KEY_ = "History.file";
+static const gchar *MAX_HISTORY_KEY_ = "History.size";
+static const gchar *HISTORY_FILE_ = NULL;
+static int MAX_HISTORY_ = 50;
+
 static void
 read_config_ (void)
 {
-  EDITOR_ = mixgtk_config_get (EDITOR_KEY_);
-  if (!EDITOR_)
+  const gchar *editor = mixgtk_config_get (EDITOR_KEY_);
+  const gchar *assem = mixgtk_config_get (MIXASM_KEY_);
+
+#ifdef HAVE_LIBHISTORY
+  const gchar *mh = mixgtk_config_get (MAX_HISTORY_KEY_);
+  if (mh) MAX_HISTORY_ = atoi (mh);
+  if (MAX_HISTORY_ <= 0) MAX_HISTORY_ = 50;
+  HISTORY_FILE_ = mixgtk_config_get (HISTORY_FILE_KEY_);
+#endif
+
+  if (!editor)
     {
       static const gchar *ENV[] = {"MDK_EDITOR", "X_EDITOR", NULL};
+      gchar *edit = NULL;
       int k = 0;
-      while (!EDITOR_ && ENV[k]) EDITOR_ = getenv (ENV[k++]);
-      if (EDITOR_) EDITOR_ = g_strconcat (EDITOR_, " %s", NULL);
+      while (!edit && ENV[k]) edit = getenv (ENV[k++]);
+      if (edit) edit = g_strconcat (edit, " %s", NULL);
+      else edit = g_strdup ("xterm -e vi %s");
+      mix_vm_cmd_dispatcher_set_editor (dis_data_.dispatcher, edit);
+      g_free (edit);
     }
-  MIXASM_ = mixgtk_config_get (MIXASM_KEY_);
-  if (!MIXASM_) MIXASM_ = "mixasm -g %s";
+  else
+    {
+      mix_vm_cmd_dispatcher_set_editor (dis_data_.dispatcher, editor);
+    }
+  if (!assem) assem = "mixasm -g %s";
+  mix_vm_cmd_dispatcher_set_assembler (dis_data_.dispatcher, assem);
+
 }
 
 static GtkWidget *ext_dlg_ = NULL;
@@ -345,8 +262,11 @@ on_external_programs_activate ()
 	(MIXGTK_EXTERNPROG_DIALOG, ASM_NAME_);
       g_assert (asm_entry_);
     }
-  gtk_entry_set_text (GTK_ENTRY (ed_entry_), EDITOR_);
-  gtk_entry_set_text (GTK_ENTRY (asm_entry_), MIXASM_);
+  gtk_entry_set_text (GTK_ENTRY (ed_entry_),
+		      mix_vm_cmd_dispatcher_get_editor (dis_data_.dispatcher));
+  gtk_entry_set_text (GTK_ENTRY (asm_entry_),
+		      mix_vm_cmd_dispatcher_get_assembler
+		      (dis_data_.dispatcher));
   gtk_widget_show (ext_dlg_);
 }
 
@@ -359,10 +279,12 @@ on_extern_cancel_button_clicked ()
 void
 on_extern_ok_button_clicked ()
 {
-  EDITOR_ = gtk_entry_get_text (GTK_ENTRY (ed_entry_));
-  MIXASM_ = gtk_entry_get_text (GTK_ENTRY (asm_entry_));
-  mixgtk_config_update (EDITOR_KEY_, EDITOR_);
-  mixgtk_config_update (MIXASM_KEY_, MIXASM_);
+  const gchar *value = gtk_entry_get_text (GTK_ENTRY (ed_entry_));
+  mix_vm_cmd_dispatcher_set_editor (dis_data_.dispatcher, value);
+  mixgtk_config_update (EDITOR_KEY_, value);
+  value = gtk_entry_get_text (GTK_ENTRY (asm_entry_));
+  mix_vm_cmd_dispatcher_set_assembler (dis_data_.dispatcher, value);
+  mixgtk_config_update (MIXASM_KEY_, value);
   gtk_widget_hide (ext_dlg_);
 }
 
@@ -411,6 +333,11 @@ mixgtk_cmd_dispatcher_init (void)
   
   if (!dis_data_.completions) init_completions_ ();
   read_config_ ();
+
+#ifdef HAVE_LIBHISTORY
+  using_history ();
+  stifle_history (MAX_HISTORY_);
+#endif
   
   return TRUE;
 }
@@ -423,7 +350,9 @@ mixgtk_cmd_dispatcher_dispatch (const gchar *command)
   g_return_if_fail (command != NULL);
   g_assert (entry != NULL);
   gtk_entry_set_text (GTK_ENTRY (entry), command);
-  on_mixvm_cmd_entry_activate (entry, NULL);
+  log_command_ (&dis_data_, command);
+  mix_vm_cmd_dispatcher_dispatch_text (dis_data_.dispatcher, command);
+  gtk_entry_set_text (GTK_ENTRY (entry), "");
 }
 
 /* get times */
@@ -445,34 +374,18 @@ mixgtk_cmd_dispatcher_get_vm (void)
   return (mix_vm_t *) mix_vm_cmd_dispatcher_get_vm (dis_data_.dispatcher);
 }
 
-/* process new command */
+/* process commands */
 void
-on_mixvm_cmd_entry_activate (GtkWidget *w, gpointer e)
+complete_command_ (void)
 {
-  gchar *text;
-  GList *cmds = NULL;
+  GtkEntry *entry = GTK_ENTRY (dis_data_.prompt);
   gchar *prefix = NULL;
-  
-  text = g_strchomp (gtk_entry_get_text (GTK_ENTRY (w)));
-
-  if (mix_vm_command_from_string (text) != MIX_CMD_INVALID)
-    {
-      mix_vm_cmd_dispatcher_dispatch_text (dis_data_.dispatcher, text);
-      gtk_entry_set_text (GTK_ENTRY (w), "");
-      return;
-    }
-
-  if (dispatch_local_command_ (&dis_data_, text))
-    {
-      gtk_entry_set_text (GTK_ENTRY (w), "");
-      return;
-    }
-  
-  cmds = g_completion_complete (dis_data_.completions, text, &prefix);
+  gchar *text = g_strchomp (gtk_entry_get_text (entry));
+  GList  *cmds = g_completion_complete (dis_data_.completions, text, &prefix);
 
   if (prefix != NULL)
     {
-      gtk_entry_set_text (GTK_ENTRY (w), prefix);
+      gtk_entry_set_text (entry, prefix);
       g_free (prefix);
       if (g_list_length (cmds) > 1)
 	{
@@ -498,14 +411,51 @@ on_mixvm_cmd_entry_activate (GtkWidget *w, gpointer e)
 			     NULL, NULL, NULL, "\n", -1);
 	}
       else
-	gtk_entry_append_text (GTK_ENTRY (w), " ");
+	gtk_entry_append_text (entry, " ");
     }
-  else
+}
+
+
+int
+on_command_prompt_key_press_event (GtkEntry *w, GdkEventKey *e, gpointer d)
+{
+  guint key = e->keyval;
+
+#ifdef HAVE_LIBHISTORY
+  HIST_ENTRY *entry = NULL;
+  if (key == GDK_Up)
     {
-      log_command_ (&dis_data_, text);
-      mix_vm_cmd_dispatcher_dispatch_text (dis_data_.dispatcher, text);
-      gtk_entry_set_text (GTK_ENTRY (w), "");
+      entry = previous_history ();
+      if (entry && entry->line)
+	gtk_entry_set_text (w, entry->line);
+      return TRUE;
     }
-}
+  if (key == GDK_Down)
+    {
+      entry = next_history ();
+      if (entry && entry->line)
+	gtk_entry_set_text (w, entry->line);
+      return TRUE;
+    }
+#endif
 
+  if (key == GDK_Tab)
+    {
+      complete_command_ ();
+      return TRUE;
+    }
 
+  if (key == GDK_Return)
+    {
+      gchar *text = gtk_entry_get_text (w);
+      if (text && *text)
+	{
+	  log_command_ (&dis_data_, text);
+	  mix_vm_cmd_dispatcher_dispatch_text (dis_data_.dispatcher, text);
+	  gtk_entry_set_text (w, "");
+	}
+      return TRUE;
+    }
+  
+  return FALSE;
+}
-- 
cgit v1.2.3