changeset 16399:f9a737fd8829

allow command-line edit function to use GUI editor * file-editor-interface.h (file_editor_interface::handle_edit_file_request): New pure virtual function. * file-editor.h, file-editor.cc (file_editor::handle_edit_file_request): New function. * octave-event-listener.h (octave_event_listenter::edit_file): New pure virtual function. * octave-qt-event-listener.h, octave-qt-event-listener.cc (octave_qt_event_listener::edit_file): New function. (octave_qt_event_listener::edit_file_signal): New signal. * main-window.h, main-window.cc (main_window::handle_edit_file_request): New function. (main_window::construct): Connect edit_file_signal to handle_edit_file_request. * __execute_edit_hook__.cc: New file. Provide Fadd_edit_hook, Fremove_edit_hook, and F__execute_edit_hook__ functions for the interpreter. * libinterp/corefcn/module.mk (COREFCN_SRC): Include it in the list. * octave-link.h, octave-link.cc (octave_link::edit_file, octave_link::do_edit_file): New functions. * octave-main-thread.cc (edit_hook_fcn): New function. (octave_main_thread::run): Install it as an edit_hook function. * miscellaneous/edit.m (do_edit): New subfunction. Allow edit request to be intercepted by edit_hook function. (edit): Use it to uniformly handle starting the editor.
author John W. Eaton <jwe@octave.org>
date Sat, 30 Mar 2013 10:57:15 -0400
parents 48b3d172042d
children 424463a80134
files libgui/src/m-editor/file-editor-interface.h libgui/src/m-editor/file-editor.cc libgui/src/m-editor/file-editor.h libgui/src/main-window.cc libgui/src/main-window.h libgui/src/octave-adapter/octave-event-listener.h libgui/src/octave-adapter/octave-link.cc libgui/src/octave-adapter/octave-link.h libgui/src/octave-adapter/octave-main-thread.cc libgui/src/octave-qt-event-listener.cc libgui/src/octave-qt-event-listener.h libinterp/corefcn/__execute_edit_hook__.cc libinterp/corefcn/module.mk scripts/miscellaneous/edit.m
diffstat 14 files changed, 252 insertions(+), 19 deletions(-) [+]
line wrap: on
line diff
--- a/libgui/src/m-editor/file-editor-interface.h	Sat Mar 30 10:56:15 2013 +0100
+++ b/libgui/src/m-editor/file-editor-interface.h	Sat Mar 30 10:57:15 2013 -0400
@@ -56,6 +56,9 @@
   virtual void handle_update_dbstop_marker_request (bool insert,
                                                     const QString& file,
                                                     int line) = 0;
+
+  virtual void handle_edit_file_request (const QString& file) = 0;
+
   virtual void set_focus () = 0;
 
 public slots:
--- a/libgui/src/m-editor/file-editor.cc	Sat Mar 30 10:56:15 2013 +0100
+++ b/libgui/src/m-editor/file-editor.cc	Sat Mar 30 10:57:15 2013 -0400
@@ -335,6 +335,12 @@
 }
 
 void
+file_editor::handle_edit_file_request (const QString& file)
+{
+  request_open_file (file);
+}
+
+void
 file_editor::request_undo ()
 {
   emit fetab_undo (_tab_widget->currentWidget ());
--- a/libgui/src/m-editor/file-editor.h	Sat Mar 30 10:56:15 2013 +0100
+++ b/libgui/src/m-editor/file-editor.h	Sat Mar 30 10:57:15 2013 -0400
@@ -135,6 +135,7 @@
   void handle_delete_debugger_pointer_request (const QString& file, int line);
   void handle_update_dbstop_marker_request (bool insert, const QString& file,
                                             int line);
+  void handle_edit_file_request (const QString& file);
 
   /** Tells the editor to react on changed settings. */
   void notice_settings ();
--- a/libgui/src/main-window.cc	Sat Mar 30 10:56:15 2013 +0100
+++ b/libgui/src/main-window.cc	Sat Mar 30 10:57:15 2013 -0400
@@ -536,6 +536,14 @@
 }
 
 void
+main_window::handle_edit_file_request (const QString& file)
+{
+#ifdef HAVE_QSCINTILLA
+  _file_editor->handle_edit_file_request (file);
+#endif
+}
+
+void
 main_window::debug_continue ()
 {
   octave_link::post_event (this, &main_window::debug_continue_callback);
@@ -1203,6 +1211,11 @@
            SIGNAL (update_dbstop_marker_signal (bool, const QString&, int)),
            this,
            SLOT (handle_update_dbstop_marker_request (bool, const QString&, int)));
+
+  connect (_octave_qt_event_listener,
+           SIGNAL (edit_file_signal (const QString&)),
+           this,
+           SLOT (handle_edit_file_request(const QString&)));
 }
 
 void
--- a/libgui/src/main-window.h	Sat Mar 30 10:56:15 2013 +0100
+++ b/libgui/src/main-window.h	Sat Mar 30 10:57:15 2013 -0400
@@ -121,6 +121,7 @@
   void handle_insert_debugger_pointer_request (const QString& file, int line);
   void handle_delete_debugger_pointer_request (const QString& file, int line);
   void handle_update_dbstop_marker_request (bool insert, const QString& file, int line);
+  void handle_edit_file_request (const QString& file);
   void debug_continue ();
   void debug_step_into ();
   void debug_step_over ();
--- a/libgui/src/octave-adapter/octave-event-listener.h	Sat Mar 30 10:56:15 2013 +0100
+++ b/libgui/src/octave-adapter/octave-event-listener.h	Sat Mar 30 10:57:15 2013 -0400
@@ -49,6 +49,8 @@
     virtual void
     update_dbstop_marker (bool insert, const std::string& file, int line) = 0;
 
+    virtual void edit_file (const std::string& file) = 0;
+
     virtual void about_to_exit () = 0;
 
     virtual void entered_debug_mode () = 0;
--- a/libgui/src/octave-adapter/octave-link.cc	Sat Mar 30 10:56:15 2013 +0100
+++ b/libgui/src/octave-adapter/octave-link.cc	Sat Mar 30 10:57:15 2013 -0400
@@ -283,6 +283,29 @@
     }
 }
 
+void
+octave_link::do_edit_file (const octave_value_list& args)
+{
+  if (event_listener)
+    {
+      if (args.length () == 1)
+        {
+          std::string file = args(0).string_value ();
+
+          if (! error_state)
+            {
+              event_listener->edit_file (file);
+              do_process_events ();
+
+            }
+          else
+            ::error ("expecting file name in edit file callback");
+        }
+      else
+        ::error ("invalid call to edit file callback");
+    }
+}
+
 bool
 octave_link::instance_ok (void)
 {
--- a/libgui/src/octave-adapter/octave-link.h	Sat Mar 30 10:56:15 2013 +0100
+++ b/libgui/src/octave-adapter/octave-link.h	Sat Mar 30 10:57:15 2013 -0400
@@ -165,6 +165,13 @@
       instance->do_update_breakpoint_hook_fcn (insert, args);
   }
 
+  static void
+  edit_file (const octave_value_list& args)
+  {
+    if (instance_ok ())
+      instance->do_edit_file (args);
+  }
+
 private:
 
   static octave_link *instance;
@@ -236,6 +243,8 @@
   void do_exit_debugger_event_hook_fcn (const octave_value_list& args);
   void do_update_breakpoint_hook_fcn (bool insert,
                                       const octave_value_list& args);
+
+  void do_edit_file (const octave_value_list& args);
 };
 
 #endif // OCTAVELINK_H
--- a/libgui/src/octave-adapter/octave-main-thread.cc	Sat Mar 30 10:56:15 2013 +0100
+++ b/libgui/src/octave-adapter/octave-main-thread.cc	Sat Mar 30 10:57:15 2013 -0400
@@ -95,6 +95,16 @@
   return retval;
 }
 
+static octave_value_list
+edit_hook_fcn (const octave_value_list& args, int)
+{
+  octave_value_list retval;
+
+  octave_link::edit_file (args);
+
+  return retval;
+}
+
 octave_main_thread::octave_main_thread () : QThread ()
 {
 }
@@ -134,6 +144,10 @@
   octave_value dbclear_fcn_handle (new octave_fcn_handle (dbclear_fcn));
   Fadd_dbclear_hook (dbclear_fcn_handle);
 
+  octave_value edit_fcn (new octave_builtin (edit_hook_fcn));
+  octave_value edit_fcn_handle (new octave_fcn_handle (edit_fcn));
+  Fadd_edit_hook (edit_fcn_handle);
+
   // Prime the history list.
   octave_link::update_history ();
 
--- a/libgui/src/octave-qt-event-listener.cc	Sat Mar 30 10:56:15 2013 +0100
+++ b/libgui/src/octave-qt-event-listener.cc	Sat Mar 30 10:57:15 2013 -0400
@@ -77,6 +77,12 @@
 }
 
 void
+octave_qt_event_listener::edit_file (const std::string& file)
+{
+  emit edit_file_signal (QString::fromStdString (file));
+}
+
+void
 octave_qt_event_listener::about_to_exit ()
 {
   qApp->quit ();
--- a/libgui/src/octave-qt-event-listener.h	Sat Mar 30 10:56:15 2013 +0100
+++ b/libgui/src/octave-qt-event-listener.h	Sat Mar 30 10:57:15 2013 -0400
@@ -40,6 +40,7 @@
   void insert_debugger_pointer (const std::string& file, int line);
   void delete_debugger_pointer (const std::string& file, int line);
   void update_dbstop_marker (bool insert, const std::string& file, int line);
+  void edit_file (const std::string& file);
   void about_to_exit ();
 
   void entered_debug_mode ();
@@ -52,6 +53,7 @@
   void insert_debugger_pointer_signal (const QString& file, int line);
   void delete_debugger_pointer_signal (const QString& file, int line);
   void update_dbstop_marker_signal (bool insert, const QString& file, int line);
+  void edit_file_signal (const QString& file);
   void entered_debug_mode_signal ();
   void quit_debug_mode_signal ();
 };
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libinterp/corefcn/__execute_edit_hook__.cc	Sat Mar 30 10:57:15 2013 -0400
@@ -0,0 +1,143 @@
+/*
+
+Copyright (C) 2013 John W. Eaton
+
+This file is part of Octave.
+
+Octave is free software; you can redistribute it and/or modify it
+under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 3 of the License, or (at
+your option) any later version.
+
+Octave is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with Octave; see the file COPYING.  If not, see
+<http://www.gnu.org/licenses/>.
+
+*/
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "defun.h"
+#include "error.h"
+#include "defun.h"
+#include "hook-fcn.h"
+#include "oct-obj.h"
+
+static hook_function_list edit_hook_functions;
+
+DEFUN (add_edit_hook, args, ,
+  "-*- texinfo -*-\n\
+@deftypefn  {Built-in Function} {@var{id} =} add_edit_hook (@var{fcn})\n\
+@deftypefnx {Built-in Function} {@var{id} =} add_edit_hook (@var{fcn}, @var{data})\n\
+Add the named function or function handle @var{fcn} to the list of functions to call\n\
+to handle editing files.  The function should have the form\n\
+\n\
+@example\n\
+@var{fcn} (@var{file}, @var{data})\n\
+@end example\n\
+\n\
+If @var{data} is omitted, Octave calls the function without one argument.\n\
+\n\
+The returned identifier may be used to remove the function handle from\n\
+the list of input hook functions.\n\
+@seealso{remove_edit_hook}\n\
+@end deftypefn")
+{
+  octave_value retval;
+
+  int nargin = args.length ();
+
+  if (nargin == 1 || nargin == 2)
+    {
+      octave_value user_data;
+
+      if (nargin == 2)
+        user_data = args(1);
+
+      hook_function hook_fcn (args(0), user_data);
+
+      if (! error_state)
+        {
+          edit_hook_functions.insert (hook_fcn.id (), hook_fcn);
+
+          retval = hook_fcn.id ();
+        }
+      else
+        error ("add_edit_hook: expecting string as first arg");
+    }
+  else
+    print_usage ();
+
+  return retval;
+}
+
+DEFUN (remove_edit_hook, args, ,
+  "-*- texinfo -*-\n\
+@deftypefn {Built-in Function} {} remove_edit_hook (@var{name})\n\
+@deftypefnx {Built-in Function} {} remove_input_event_hook (@var{fcn_id})\n\
+Remove the named function or function handle with the given identifier\n\
+from the list of functions to call to handle editing files.\n\
+@seealso{add_edit_hook}\n\
+@end deftypefn")
+{
+  octave_value_list retval;
+
+  int nargin = args.length ();
+
+  if (nargin == 1 || nargin == 2)
+    {
+      std::string hook_fcn_id = args(0).string_value ();
+
+      bool warn = (nargin < 2);
+
+      if (! error_state)
+        {
+          hook_function_list::iterator p
+            = edit_hook_functions.find (hook_fcn_id);
+
+          if (p != edit_hook_functions.end ())
+            edit_hook_functions.erase (p);
+          else if (warn)
+            warning ("remove_edit_hook: %s not found in list",
+                     hook_fcn_id.c_str ());
+        }
+      else
+        error ("remove_edit_hook: argument not valid as a hook function name or id");
+    }
+  else
+    print_usage ();
+
+  return retval;
+}
+
+DEFUN (__execute_edit_hook__, args, ,
+  "-*- texinfo -*-\n\
+@deftypefn {Built-in Function} {@var{status} =} __execute_edit_hook__ (@var{file})\n\
+Undocumented internal function.\n\
+@end deftypefn")
+{
+  octave_value retval;
+
+  if (edit_hook_functions.empty ())
+    retval = false;
+  else
+    {
+      edit_hook_functions.run (args);
+
+      retval = true;
+    }
+
+  return retval;
+}
+
+/*
+## No test needed for internal helper function.
+%!assert (1)
+*/
--- a/libinterp/corefcn/module.mk	Sat Mar 30 10:56:15 2013 +0100
+++ b/libinterp/corefcn/module.mk	Sat Mar 30 10:57:15 2013 -0400
@@ -27,6 +27,7 @@
 COREFCN_SRC = \
   corefcn/__contourc__.cc \
   corefcn/__dispatch__.cc \
+  corefcn/__execute_edit_hook__.cc \
   corefcn/__lin_interpn__.cc \
   corefcn/__pchip_deriv__.cc \
   corefcn/__qp__.cc \
--- a/scripts/miscellaneous/edit.m	Sat Mar 30 10:56:15 2013 +0100
+++ b/scripts/miscellaneous/edit.m	Sat Mar 30 10:57:15 2013 -0400
@@ -241,13 +241,16 @@
 
   ## Start the editor without a file if no file is given.
   if (nargin < 1)
-    if (exist (FUNCTION.HOME, "dir") == 7 && (isunix () || ! ispc ()))
-      system (cstrcat ("cd \"", FUNCTION.HOME, "\" ; ",
-                      sprintf (undo_string_escapes (FUNCTION.EDITOR), "")),
-              [], FUNCTION.MODE);
+    if (exist (FUNCTION.HOME, "dir") == 7)
+      curr_dir = pwd ();
+      unwind_protect
+        chdir (FUNCTION.HOME);
+        do_edit (FUNCTION.EDITOR, "", FUNCTION.MODE);
+      unwind_protect_cleanup
+        chdir (curr_dir);
+      end_unwind_protect
     else
-      system (sprintf (undo_string_escapes (FUNCTION.EDITOR), ""),
-              [], FUNCTION.MODE);
+      do_edit (FUNCTION.EDITOR, "", FUNCTION.MODE);
     endif
     return;
   endif
@@ -329,9 +332,7 @@
       ## If the file exists, then edit it.
       if (FUNCTION.EDITINPLACE)
         ## Edit in place even if it is protected.
-        system (sprintf (undo_string_escapes (FUNCTION.EDITOR),
-                         cstrcat ("\"", fileandpath, "\"")),
-                [], FUNCTION.MODE);
+        do_edit (FUNCTION.EDITOR, fileandpath, FUNCTION.MODE);
         return;
       else
         ## If the file is modifiable in place then edit it, otherwise make
@@ -347,9 +348,7 @@
         else
           fclose (fid);
         endif
-        system (sprintf (undo_string_escapes (FUNCTION.EDITOR),
-                         cstrcat ("\"", fileandpath, "\"")),
-                [], FUNCTION.MODE);
+        do_edit (FUNCTION.EDITOR, fileandpath, FUNCTION.MODE);
         return;
       endif
     endif
@@ -364,9 +363,7 @@
       case {"cc", "m"}
         0;
       otherwise
-        system (sprintf (undo_string_escapes (FUNCTION.EDITOR),
-                         cstrcat ("\"", fileandpath, "\"")),
-                [], FUNCTION.MODE);
+        do_edit (FUNCTION.EDITOR, fileandpath, FUNCTION.MODE);
         return;
     endswitch
 
@@ -515,10 +512,7 @@
     fputs (fid, text);
     fclose (fid);
 
-    ## Finally we are ready to edit it!
-    system (sprintf (undo_string_escapes (FUNCTION.EDITOR),
-                     cstrcat ("\"", fileandpath, "\"")),
-            [], FUNCTION.MODE);
+    do_edit (FUNCTION.EDITOR, fileandpath, FUNCTION.MODE);
             
   endif
 
@@ -564,6 +558,21 @@
 
 endfunction
 
+function do_edit (editor, file, mode)
+
+  ## Give the hook function a chance.  If that fails, fall back
+  ## on running an editor with the system function.
+
+  status = __execute_edit_hook__ (file);
+
+  if (! status)
+    system (sprintf (undo_string_escapes (editor),
+                     cstrcat ("\"", file, "\"")),
+            [], mode);
+  endif
+
+endfunction
+
 
 %!test
 %! s.editor = edit ("get", "editor");