From b45f21075d51b6b20a1e2a7ae6ba14fae3935fad Mon Sep 17 00:00:00 2001
From: Jose Antonio Ortega Ruiz <jao@gnu.org>
Date: Mon, 4 Jun 2001 22:13:59 +0000
Subject: edit and compile commands added to gmixvm

---
 NEWS                           |   4 +
 mixgtk/mixgtk.glade            |  10 ++
 mixgtk/mixgtk_cmd_dispatcher.c | 228 ++++++++++++++++++++++++++++++++++++-----
 mixgtk/mixgtk_mixvm.h          |   1 +
 mixgtk/mixgtk_widgets.c        |   3 +-
 mixgtk/mixgtk_widgets.h        |   3 +-
 mixlib/mix_file.c              |  10 ++
 mixlib/mix_file.h              |   4 +
 samples/primes.mixal           |   1 -
 9 files changed, 238 insertions(+), 26 deletions(-)

diff --git a/NEWS b/NEWS
index a5b1436..2785fb6 100644
--- a/NEWS
+++ b/NEWS
@@ -13,6 +13,10 @@ Please send mdk bug reports to bug-mdk@gnu.org.
 
 ** The main gmixvm window is not shown until it is completely drawn.
 
+** The commands 'edit' and 'compile' are now understood by gmixvm. The
+   external programs used can be configured using the menu entry
+   Settings->External programs.
+
 ** 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).
diff --git a/mixgtk/mixgtk.glade b/mixgtk/mixgtk.glade
index 6676fbd..a0dcfcf 100644
--- a/mixgtk/mixgtk.glade
+++ b/mixgtk/mixgtk.glade
@@ -2586,6 +2586,11 @@
 	  <name>extern_cancel_button</name>
 	  <can_default>True</can_default>
 	  <can_focus>True</can_focus>
+	  <signal>
+	    <name>clicked</name>
+	    <handler>on_extern_cancel_button_clicked</handler>
+	    <last_modification_time>Mon, 04 Jun 2001 21:31:50 GMT</last_modification_time>
+	  </signal>
 	  <label>_Cancel</label>
 	  <relief>GTK_RELIEF_NORMAL</relief>
 	</widget>
@@ -2595,6 +2600,11 @@
 	  <name>extern_ok_button</name>
 	  <can_default>True</can_default>
 	  <can_focus>True</can_focus>
+	  <signal>
+	    <name>clicked</name>
+	    <handler>on_extern_ok_button_clicked</handler>
+	    <last_modification_time>Mon, 04 Jun 2001 21:32:21 GMT</last_modification_time>
+	  </signal>
 	  <label>_OK</label>
 	  <relief>GTK_RELIEF_NORMAL</relief>
 	</widget>
diff --git a/mixgtk/mixgtk_cmd_dispatcher.c b/mixgtk/mixgtk_cmd_dispatcher.c
index d53e991..bb1d4db 100644
--- a/mixgtk/mixgtk_cmd_dispatcher.c
+++ b/mixgtk/mixgtk_cmd_dispatcher.c
@@ -24,18 +24,20 @@
 #include <stdlib.h>
 #include <stdio.h>
 #include <string.h>
+#include <ctype.h>
 #include <unistd.h>
 #include <fcntl.h>
 #include <errno.h>
 
 #include <mixlib/mix_vm_command.h>
-#include "mixgtk_cmd_dispatcher.h"
 #include "mixgtk_mixvm.h"
 #include "mixgtk_mixal.h"
+#include "mixgtk_config.h"
+#include "mixgtk_cmd_dispatcher.h"
 
 
 /* a mix vm command dispatcher */
-struct mixgtk_dispatch_
+typedef struct mixgtk_dispatch_
 {
   mix_vm_cmd_dispatcher_t *dispatcher; /* the underlying cmd dispatcher */
   FILE *out;			/* the dispatcher's output file */
@@ -45,10 +47,128 @@ struct mixgtk_dispatch_
   GtkWidget *status;		/* the status bar widget */
   guint context;		/* context of the status bar messages */
   GCompletion *completions;	/* mixvm command completions */
-};
+} mixgtk_dispatch_data_t;
 
 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);
+}
+
+static void
+flush_log_ (mixgtk_dispatch_data_t *dis)
+{
+  enum {BLKSIZE = 100};
+  static gchar BUFFER[BLKSIZE];
+  
+  ssize_t k;
+  fflush (dis->out);
+  while ((k = read (dis->fildes[0], BUFFER, BLKSIZE)) != 0)
+    {
+      if (k == -1 && errno != EINTR) break;
+      if (k != -1)
+	gtk_text_insert (GTK_TEXT (dis->log), NULL, NULL, NULL,
+			 BUFFER, k);
+    }
+}
+
+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)
@@ -59,10 +179,12 @@ 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 */
+/* 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)
@@ -86,24 +208,13 @@ global_pre_hook_ (mix_vm_cmd_dispatcher_t *dis,
 		       _("\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)
 {
-  enum {BLKSIZE = 100};
-  static gchar BUFFER[BLKSIZE];
-  
-  ssize_t k;
-  fflush (dis_data_.out);
-  while ((k = read (dis_data_.fildes[0], BUFFER, BLKSIZE)) != 0)
-    {
-      if (k == -1 && errno != EINTR) break;
-      if (cmd < MIX_CMD_INVALID)
-	gtk_text_insert (GTK_TEXT (dis_data_.log), NULL, NULL, NULL,
-			 BUFFER, k);
-    }
-
+  flush_log_ ((mixgtk_dispatch_data_t *)data);
   mixgtk_mixvm_update_vm_widgets ();
 }
 
@@ -168,10 +279,9 @@ allbp_post_hook_ (mix_vm_cmd_dispatcher_t *dis, const gchar *arg,
 static void
 install_hooks_ (void)
 {
-  mix_vm_cmd_dispatcher_global_pre_hook (dis_data_.dispatcher,
-					 global_pre_hook_, NULL);
   mix_vm_cmd_dispatcher_global_post_hook (dis_data_.dispatcher,
-					  global_post_hook_, NULL);
+					  global_post_hook_,
+					  (gpointer)(&dis_data_));
   mix_vm_cmd_dispatcher_post_hook (dis_data_.dispatcher,
 				   MIX_CMD_LOAD, load_post_hook_,
 				   NULL);
@@ -198,6 +308,63 @@ install_hooks_ (void)
 				   NULL);
 }
 
+/* configuration stuff */
+static void
+read_config_ (void)
+{
+  EDITOR_ = mixgtk_config_get (EDITOR_KEY_);
+  if (!EDITOR_)
+    {
+      static const gchar *ENV[] = {"MDK_EDITOR", "X_EDITOR", NULL};
+      int k = 0;
+      while (!EDITOR_ && ENV[k]) EDITOR_ = getenv (ENV[k++]);
+      if (EDITOR_) EDITOR_ = g_strconcat (EDITOR_, " %s", NULL);
+    }
+  MIXASM_ = mixgtk_config_get (MIXASM_KEY_);
+  if (!MIXASM_) MIXASM_ = "mixasm -g %s";
+}
+
+static GtkWidget *ext_dlg_ = NULL;
+static GtkWidget *ed_entry_ = NULL;
+static GtkWidget *asm_entry_ = NULL;
+
+static const gchar *ED_NAME_ = "editor_entry";
+static const gchar *ASM_NAME_ = "mixasm_entry";
+
+void
+on_external_programs_activate ()
+{
+  if (!ext_dlg_)
+    {
+      ext_dlg_ = mixgtk_widget_factory_get_dialog (MIXGTK_EXTERNPROG_DIALOG);
+      g_return_if_fail (ext_dlg_ != NULL);
+      ed_entry_ = mixgtk_widget_factory_get_child_by_name
+	(MIXGTK_EXTERNPROG_DIALOG, ED_NAME_);
+      g_assert (ed_entry_);
+      asm_entry_ = mixgtk_widget_factory_get_child_by_name
+	(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_widget_show (ext_dlg_);
+}
+
+void
+on_extern_cancel_button_clicked ()
+{
+  gtk_widget_hide (ext_dlg_);
+}
+
+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_);
+  gtk_widget_hide (ext_dlg_);
+}
 
 /* initialise the command dispatcher */
 gboolean
@@ -215,6 +382,10 @@ mixgtk_cmd_dispatcher_init (void)
     {
       int r = pipe (dis_data_.fildes);
       g_return_val_if_fail (r == 0, FALSE);
+      /* connect stdout/stderr to the pipe's write end */
+      if (dup2 (dis_data_.fildes[1], STDOUT_FILENO) == -1
+	  || dup2 (dis_data_.fildes[1], STDERR_FILENO) == -1)
+	return FALSE;
       dis_data_.out = fdopen (dis_data_.fildes[1], "w");
       g_return_val_if_fail (dis_data_.out != NULL, FALSE);
       r = fcntl (dis_data_.fildes[0], F_GETFL, 0);
@@ -225,6 +396,7 @@ mixgtk_cmd_dispatcher_init (void)
       dis_data_.dispatcher =
 	mix_vm_cmd_dispatcher_new (dis_data_.out, dis_data_.out);
       mix_vm_cmd_dispatcher_print_time (dis_data_.dispatcher, FALSE);
+      
       install_hooks_ ();
     }
   
@@ -238,6 +410,7 @@ mixgtk_cmd_dispatcher_init (void)
     }
   
   if (!dis_data_.completions) init_completions_ ();
+  read_config_ ();
   
   return TRUE;
 }
@@ -266,7 +439,7 @@ mixgtk_cmd_dispatcher_get_times (gint *uptime, gint *progtime, gint *laptime)
 }
 
 /* get the underlying vm */
-extern mix_vm_t *
+mix_vm_t *
 mixgtk_cmd_dispatcher_get_vm (void)
 {
   return (mix_vm_t *) mix_vm_cmd_dispatcher_get_vm (dis_data_.dispatcher);
@@ -280,14 +453,20 @@ on_mixvm_cmd_entry_activate (GtkWidget *w, gpointer e)
   GList *cmds = NULL;
   gchar *prefix = NULL;
   
-  text = gtk_entry_get_text (GTK_ENTRY (w));
+  text = g_strchomp (gtk_entry_get_text (GTK_ENTRY (w)));
 
-  if (mix_vm_command_from_string (g_strchomp (text)) != MIX_CMD_INVALID)
+  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);
 
@@ -323,7 +502,10 @@ on_mixvm_cmd_entry_activate (GtkWidget *w, gpointer e)
     }
   else
     {
+      log_command_ (&dis_data_, text);
       mix_vm_cmd_dispatcher_dispatch_text (dis_data_.dispatcher, text);
       gtk_entry_set_text (GTK_ENTRY (w), "");
     }
 }
+
+
diff --git a/mixgtk/mixgtk_mixvm.h b/mixgtk/mixgtk_mixvm.h
index 8207d91..04d210a 100644
--- a/mixgtk/mixgtk_mixvm.h
+++ b/mixgtk/mixgtk_mixvm.h
@@ -26,6 +26,7 @@
 #define MIXGTK_MIXVM_H
 
 #include <mixlib/mix_vm.h>
+#include "mixgtk.h"
 
 /* initialise the mixvm widgets */
 extern gboolean
diff --git a/mixgtk/mixgtk_widgets.c b/mixgtk/mixgtk_widgets.c
index b032898..d5ac7b1 100644
--- a/mixgtk/mixgtk_widgets.c
+++ b/mixgtk/mixgtk_widgets.c
@@ -37,7 +37,8 @@ static const gchar * dnames_[] = {
   "color_dialog",
   "colorsel_dialog",
   "fontsel_dialog",
-  "devform_dialog"
+  "devform_dialog",
+  "external_dialog"
 };
 
 #define DLG_NO_ (sizeof (dnames_) / sizeof(dnames_[0]))
diff --git a/mixgtk/mixgtk_widgets.h b/mixgtk/mixgtk_widgets.h
index 261ad12..ed7cf7e 100644
--- a/mixgtk/mixgtk_widgets.h
+++ b/mixgtk/mixgtk_widgets.h
@@ -37,7 +37,8 @@ typedef enum {
   MIXGTK_COLOR_DIALOG,    /* color customization dialog */
   MIXGTK_COLORSEL_DIALOG, /* color selection dialog */
   MIXGTK_FONTSEL_DIALOG,  /* font selection dialog */
-  MIXGTK_DEVFORM_DIALOG		/* device format config dialog */
+  MIXGTK_DEVFORM_DIALOG,  /* device format config dialog */
+  MIXGTK_EXTERNPROG_DIALOG	/* external programs dialog */
 } mixgtk_dialog_id_t;
 
 /* enumeration of mixvm widget ids */
diff --git a/mixlib/mix_file.c b/mixlib/mix_file.c
index ac623f6..816a380 100644
--- a/mixlib/mix_file.c
+++ b/mixlib/mix_file.c
@@ -133,6 +133,16 @@ mix_file_to_FILE(const mix_file_t *file)
   return io_get_FILE_(file);
 }
 
+/* complete a name with an extension, if needed */
+gchar *
+mix_file_complete_name (const gchar *name, const gchar *extension)
+{
+  if (!name) return NULL;
+  if (!extension || !needs_completion_ (name, extension))
+    return g_strdup (name);
+  return add_completion_ (name, extension);
+}
+
 /* Get the base name and extension of file */
 const gchar *
 mix_file_base_name(const mix_file_t *file)
diff --git a/mixlib/mix_file.h b/mixlib/mix_file.h
index a4bac12..bb9e7e3 100644
--- a/mixlib/mix_file.h
+++ b/mixlib/mix_file.h
@@ -49,6 +49,10 @@ mix_file_to_FILE(const mix_file_t *file);
 /* standard default extensions */
 extern const gchar *MIX_SRC_DEFEXT, *MIX_LIST_DEFEXT, *MIX_CODE_DEFEXT;
 
+/* complete a name with an extension, if needed */
+extern gchar *
+mix_file_complete_name (const gchar *name, const gchar *extension);
+
 /* Get the base name and extension of file */
 extern const gchar *
 mix_file_base_name(const mix_file_t *file);
diff --git a/samples/primes.mixal b/samples/primes.mixal
index d8e6eef..d2de8c0 100644
--- a/samples/primes.mixal
+++ b/samples/primes.mixal
@@ -51,4 +51,3 @@ TITLE	ALF	"FIRST"
 	CON	BUF0+10
 	END	START
 
-                             
\ No newline at end of file
-- 
cgit v1.2.3