diff libgui/src/m-editor/octave-qscintilla.cc @ 27556:410622ac120f

improve run selection from editor (bug #42705) * file-editor-tab.cc (file_editor_tab): relay interpreter event signals to the ones of the editor widget * file-editor.cc (make_file_editor_tab): connect signal of edit area for giving focus to console window to the new slot in main_window * octave-qscintilla.cc: include headers required for interpreter threads and for additionally used Qt libs; (octave_qscintilla): connect new signals for finished run selection action to the new related slot; (contextmenu_run_temp_error): new method displaying a message box on error handling temp. files; (contextmenu_run): create a temp. file with all selected lines extended by commands for displaying each line and add it to the command history, disable opening a file at breakpoints, run this temp. file by the interpreter and emit new signal when running this file is finished; (ctx_menu_run_finished): slot when running the temp. file is finished, removing temp. files and reset modified editor preferences; * octave-qscintilla.h: include QSettings and interpreter-events, interpreter signal, signal for focusing console window and signal when running temp file is finished, new slot for the latter * main-window.cc (focus_console_after_command): do not return the related setting, but actually give console window the focus if desired, (run_file_in_terminal, execute_command_in_terminal): use this new form * main-window.h: change focus_console_method from private method into public slot * resource-manager.cc (resource_manager): initialize new list of created temp. files; (~resource_manager): remove any temp. files that are still existing; (do_create_tmp_file): create a new temp. file with the given contents and store its smart pointer into a list for removing the file later; (do_remove_tmp_file): remove given temp. file and remove it from the list; * resource-manager.h: include QPointer and QTemporaryFile, (create_tmp_file): new static method calling internal do_create_tmp_file; (remove_tmp_file): new static method calling internal do_create_tmp_file; new internal methods do_create_tmp_file and do_remove_tmp_file, new list for storing temp. file pointers
author Torsten Lilge <ttl-octave@mailbox.org>
date Fri, 25 Oct 2019 07:36:37 +0200
parents 15752c577f6d
children 3fcc650de22f
line wrap: on
line diff
--- a/libgui/src/m-editor/octave-qscintilla.cc	Thu Oct 24 22:33:37 2019 +0200
+++ b/libgui/src/m-editor/octave-qscintilla.cc	Fri Oct 25 07:36:37 2019 +0200
@@ -20,7 +20,7 @@
 
 */
 
-// Author: Torsten <ttl@justmail.de>
+// Author: Torsten Lilge <ttl-octave@mailbox.org>
 
 #if defined (HAVE_CONFIG_H)
 #  include "config.h"
@@ -30,7 +30,9 @@
 
 #include <Qsci/qscilexer.h>
 
+#include <QDir>
 #include <QKeySequence>
+#include <QMessageBox>
 #include <QMimeData>
 #include <QShortcut>
 #include <QToolTip>
@@ -57,6 +59,11 @@
 #include "resource-manager.h"
 #include "shortcut-manager.h"
 
+#include "builtin-defun-decls.h"
+#include "cmd-edit.h"
+#include "interpreter-private.h"
+#include "interpreter.h"
+
 // Return true if CANDIDATE is a "closing" that matches OPENING,
 // such as "end" or "endif" for "if", or "catch" for "try".
 // Used for testing the last word of an "if" etc. line,
@@ -112,6 +119,12 @@
     connect (this, SIGNAL (cursorPositionChanged (int, int)),
              this, SLOT (cursor_position_changed (int, int)));
 
+    connect (this, SIGNAL (ctx_menu_run_finished_signal (bool, QTemporaryFile*,
+                                                         QTemporaryFile*, QTemporaryFile*)),
+             this, SLOT (ctx_menu_run_finished (bool, QTemporaryFile*,
+                                                QTemporaryFile*, QTemporaryFile*)),
+             Qt::QueuedConnection);
+
     // clear scintilla edit shortcuts that are handled by the editor
     QsciCommandSet *cmd_set = standardCommands ();
 
@@ -748,14 +761,152 @@
     emit context_menu_edit_signal (m_word_at_cursor);
   }
 
+  void octave_qscintilla::contextmenu_run_temp_error (void)
+  {
+    QMessageBox::critical (this, tr ("Octave Editor"),
+                        tr ("Creating temporary files failed.\n"
+                            "Make sure you have write access to temp. directory\n"
+                             "%1\n\n"
+                             "\"Run Selection\" requires temporary files.").arg (QDir::tempPath ()));
+  }
+
   void octave_qscintilla::contextmenu_run (bool)
   {
-    QStringList commands = selectedText ().split (QRegExp ("[\r\n]"),
-                                                  QString::SkipEmptyParts);
-    for (int i = 0; i < commands.size (); i++)
-      emit execute_command_in_terminal_signal (commands.at (i));
+
+    // Create tmp file required for adding command to history
+    QPointer<QTemporaryFile> tmp_hist
+        = resource_manager::create_tmp_file (); // empty tmp file for history
+
+    // Create tmp file required for the script echoing and adding cmd to hist
+    QPointer<QTemporaryFile> tmp_script
+        = resource_manager::create_tmp_file ("m"); // tmp script file
+
+    bool tmp = (tmp_hist && tmp_hist->open () &&
+                tmp_script && tmp_script->open());
+    if (! tmp)
+      {
+        // tmp files not working: use old way to run selection
+        contextmenu_run_temp_error ();
+        return;
+      }
+
+    tmp_hist->close ();
+
+    QString tmp_hist_name = QFileInfo (tmp_hist->fileName ()).baseName ();
+    QString tmp_script_name = QFileInfo (tmp_script->fileName ()).baseName ();
+
+    // Create tmp file with script for echoing a command and adding
+    // the the history
+    QString echo_hist = QString (
+        "function cnt = %2 (oldcnt, i, command, line)\n"
+        "   cnt = oldcnt;\n"
+        "   if cnt < i\n"
+        "       cnt = i;\n"
+        "       disp ([PS1, command]);\n"
+        "       if (history_save ())\n"
+        "           fid = fopen ('%1','w');\n"
+        "           if (fid != -1)\n"
+        "               fprintf (fid, [line,'\\n']);\n"
+        "               fclose (fid);\n"
+        "           end;\n"
+        "           history -r '%1'\n"
+        "       end\n"
+        "   end\n"
+        " end\n").arg (tmp_hist->fileName ()).arg (tmp_script_name);
+
+    tmp_script->write (echo_hist.toUtf8 ());
+    tmp_script->close ();
+
+    // Take selected code and extend it by commands for echoing each
+    // evaluated line and for adding the line to the history (use script)
+
+    QString tmp_dir = QFileInfo (tmp_script->fileName ()).absolutePath ();
+    QString code = QString ("%1 = -1;\n\n").arg (tmp_hist_name);
+
+    // Split contents into single lines and complete commands
+    QStringList lines = selectedText ().split (QRegExp ("[\r\n]"),
+                                               QString::SkipEmptyParts);
+
+    for (int i = 0; i < lines.count (); i++)
+      {
+        QString line = lines.at (i);
+        line = line.replace (QString ("%"), QString ("%%"));
+
+        code += QString ("%1 = %2 (%1, %3, '%4', '%5');\n"
+                         "%4\n\n")
+                         .arg (tmp_hist_name)
+                         .arg (tmp_script_name)
+                         .arg (i)
+                         .arg (lines.at (i))
+                         .arg (line);
+      }
+
+    code += QString ("clear %1 %2_fcn;\n")
+                     .arg (tmp_hist_name).arg (tmp_script_name);
+
+    // Create tmp file with the code to be executed by the interpreter
+    QPointer<QTemporaryFile> tmp_file
+        = resource_manager::create_tmp_file ("m", code);
+
+    tmp = (tmp_file && tmp_file->open ());
+    if (! tmp)
+      {
+        // tmp files not working: use old way to run selection
+        contextmenu_run_temp_error ();
+        return;
+      }
+    tmp_file->close ();
+
+    // Disable opening a file at a breakpoint in case keyboard () is used
+    QSettings* settings = resource_manager::get_settings ();
+    bool show_dbg_file = settings->value (ed_show_dbg_file.key,
+                                       ed_show_dbg_file.def).toBool ();
+    settings->setValue (ed_show_dbg_file.key, false);
+
+    emit focus_console_after_command_signal ();
+
+    // Let the interpreter execute the tmp file
+    emit interpreter_event
+      ([this, tmp_file, tmp_hist, tmp_script, show_dbg_file] (interpreter& interp)
+       {
+         // INTERPRETER THREAD
+
+         std::string file = tmp_file->fileName ().toStdString ();
+
+         std::string pending_input = command_editor::get_current_line ();
+
+         // Add tmp dir to the path for echo/hist script
+         octave_value_list path =
+            ovl (QFileInfo (tmp_script->fileName ()).absolutePath ().toStdString ());
+         Faddpath (interp, path);
+         interp.source_file (file);
+         Frmpath (interp, path);
+
+         command_editor::replace_line ("");
+         command_editor::set_initial_input (pending_input);
+         command_editor::redisplay ();
+         command_editor::interrupt_event_loop ();
+         command_editor::accept_line ();
+
+         // Done, restore settings and remove tmp files
+         emit ctx_menu_run_finished_signal (show_dbg_file,
+                                            tmp_file, tmp_hist, tmp_script);
+       });
   }
 
+  void octave_qscintilla::ctx_menu_run_finished (bool show_dbg_file,
+                                                 QTemporaryFile* tmp_file,
+                                                 QTemporaryFile* tmp_hist,
+                                                 QTemporaryFile* tmp_script)
+  {
+    QSettings *settings = resource_manager::get_settings ();
+    settings->setValue (ed_show_dbg_file.key, show_dbg_file);
+    resource_manager::remove_tmp_file (tmp_file);
+    resource_manager::remove_tmp_file (tmp_hist);
+    resource_manager::remove_tmp_file (tmp_script);
+  }
+
+
   // wrappers for dbstop related context menu items
 
   // FIXME: Why can't the data be sent as the argument to the function???