# HG changeset patch # User John W. Eaton # Date 1364655435 14400 # Node ID f9a737fd8829b31d714bfbc9888a7d49d4ba1068 # Parent 48b3d172042de33b3ca0e2beb578ec7653ea6767 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. diff -r 48b3d172042d -r f9a737fd8829 libgui/src/m-editor/file-editor-interface.h --- 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: diff -r 48b3d172042d -r f9a737fd8829 libgui/src/m-editor/file-editor.cc --- 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 ()); diff -r 48b3d172042d -r f9a737fd8829 libgui/src/m-editor/file-editor.h --- 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 (); diff -r 48b3d172042d -r f9a737fd8829 libgui/src/main-window.cc --- 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 diff -r 48b3d172042d -r f9a737fd8829 libgui/src/main-window.h --- 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 (); diff -r 48b3d172042d -r f9a737fd8829 libgui/src/octave-adapter/octave-event-listener.h --- 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; diff -r 48b3d172042d -r f9a737fd8829 libgui/src/octave-adapter/octave-link.cc --- 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) { diff -r 48b3d172042d -r f9a737fd8829 libgui/src/octave-adapter/octave-link.h --- 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 diff -r 48b3d172042d -r f9a737fd8829 libgui/src/octave-adapter/octave-main-thread.cc --- 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 (); diff -r 48b3d172042d -r f9a737fd8829 libgui/src/octave-qt-event-listener.cc --- 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 (); diff -r 48b3d172042d -r f9a737fd8829 libgui/src/octave-qt-event-listener.h --- 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 (); }; diff -r 48b3d172042d -r f9a737fd8829 libinterp/corefcn/__execute_edit_hook__.cc --- /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 +. + +*/ + +#ifdef HAVE_CONFIG_H +#include +#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) +*/ diff -r 48b3d172042d -r f9a737fd8829 libinterp/corefcn/module.mk --- 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 \ diff -r 48b3d172042d -r f9a737fd8829 scripts/miscellaneous/edit.m --- 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");