diff libgui/src/m-editor/file-editor-tab.cc @ 27401:1f595192b5a5

attempt to avoid threading issues when updating lexer in file editor tab * file-editor-tab.h, file-editor-tab.cc (file_editor_tab::m_prep_apis_path): New data member. (file_editor_tab::handle_add_octave_apis): Rename from add_octave_apis and declare as private slot. Accept QStringList instead of octave_value_list. (file_editor_tab::handle_api_entries_added): New slot. Finish setup of m_lexer_apis. (file_editor_tab::request_add_octave_apis, file_editor_tab::api_entries_added): New signals. (file_editor_tab::file_editor_tab): Connect api_entries_added signal to handle_api_entries_added slot. (file_editor_tab::update_lexer): Connect request_add_octave_apis signal to handle_add_octave_apis slot. (file_editor_tab::update_lexer_settings): Don't attempt to process everything in the GUI thread. Instead, emit a signal to get symbol lists in the interpreter thread, then emit another signal to add them to the lexer in the GUI thread, and finally another to finish the m_lexer_apis setup.
author John W. Eaton <jwe@octave.org>
date Thu, 12 Sep 2019 17:13:28 -0400
parents fe6a64dc8605
children 27967cb3dea5
line wrap: on
line diff
--- a/libgui/src/m-editor/file-editor-tab.cc	Thu Sep 12 17:01:34 2019 -0400
+++ b/libgui/src/m-editor/file-editor-tab.cc	Thu Sep 12 17:13:28 2019 -0400
@@ -235,6 +235,8 @@
     connect (this, SIGNAL (request_add_breakpoint (int, const QString&)),
              this, SLOT (handle_request_add_breakpoint (int, const QString&)));
 
+    connect (this, SIGNAL (api_entries_added (void)),
+             this, SLOT (handle_api_entries_added (void)));
     QSettings *settings = resource_manager::get_settings ();
     if (settings)
       notice_settings (settings, true);
@@ -643,6 +645,9 @@
         // build information for auto completion (APIs)
         m_lexer_apis = new QsciAPIs (lexer);
 
+        connect (this, SIGNAL (request_add_octave_apis (const QStringList&)),
+                 this, SLOT (handle_add_octave_apis (const QStringList&)));
+
         // Get the settings for this new lexer
         update_lexer_settings ();
       }
@@ -685,8 +690,8 @@
 
         QCoreApplication::setApplicationName ("octave");  // Set temp. name
 
-        QString prep_apis_path = local_data_path + "/"
-                                  + QString (OCTAVE_VERSION) + "/qsci/";
+        m_prep_apis_path
+          = local_data_path + "/" + QString (OCTAVE_VERSION) + "/qsci/";
 
         // get settings which infos are used for octave
         bool octave_builtins
@@ -704,7 +709,7 @@
             // completed, the date of any existing file is checked.
 
             // Keywords are always used
-            m_prep_apis_file = prep_apis_path + lexer->lexer () + "_k";
+            m_prep_apis_file = m_prep_apis_path + lexer->lexer () + "_k";
 
             // Buitlins are only used if the user settings say so
             if (octave_builtins)
@@ -717,6 +722,7 @@
 
             // check whether the APIs info needs to be prepared and saved
             QFileInfo apis_file = QFileInfo (m_prep_apis_file);
+
             // flag whether apis file needs update
             update_apis = ! apis_file.exists ();
 
@@ -731,11 +737,10 @@
               }
 
           }
-        else  // no octave file, just add extension
+        else
           {
-
-            m_prep_apis_file = prep_apis_path + lexer->lexer () + ".pap";
-
+            // No octave file, just add extension.
+            m_prep_apis_file = m_prep_apis_path + lexer->lexer () + ".pap";
           }
 
         // Make sure the apis file is usable, otherwise the gui might crash,
@@ -758,56 +763,67 @@
             // no prepared info was loaded, prepare and save if possible
 
             // create raw apis info
-            QString keyword;
-            QStringList keyword_list;
-            int i,j;
 
             if (m_is_octave_file)
               {
-                // FIXME: the following does not appear to be thread safe.
-
-                // octave: get keywords from internal informations depending on
-                //         user preferences
-
-                // keywords are always used
-                add_octave_apis (Fiskeyword ());            // add new entries
-
-                interpreter& interp
-                  = __get_interpreter__ ("file_editor_tab::update_lexer_settings");
-
-                if (octave_builtins)
-                  add_octave_apis (F__builtins__ (interp));       // add new entries
-
-                if (octave_functions)
-                  add_octave_apis (F__list_functions__ (interp)); // add new entries
-
+                emit interpreter_event
+                  ([this, octave_functions, octave_builtins] (interpreter& interp)
+                   {
+                     QStringList api_entries;
+
+                     octave_value_list tmp = Fiskeyword ();
+                     const Cell ctmp = tmp(0).cell_value ();
+                     for (octave_idx_type i = 0; i < ctmp.numel (); i++)
+                       {
+                         std::string kw = ctmp(i).string_value ();
+                         api_entries.append (QString::fromStdString (kw));
+                       }
+
+                     if (octave_builtins)
+                       {
+                         symbol_table& symtab = interp.get_symbol_table ();
+
+                         string_vector bfl = symtab.built_in_function_names ();
+
+                         for (octave_idx_type i = 0; i < bfl.numel (); i++)
+                           api_entries.append (QString::fromStdString (bfl[i]));
+                       }
+
+
+                     if (octave_functions)
+                       {
+                         load_path& lp = interp.get_load_path ();
+
+                         string_vector ffl = lp.fcn_names ();
+                         string_vector afl = interp.autoloaded_functions ();
+
+                         for (octave_idx_type i = 0; i < ffl.numel (); i++)
+                           api_entries.append (QString::fromStdString (ffl[i]));
+
+                         for (octave_idx_type i = 0; i < afl.numel (); i++)
+                           api_entries.append (QString::fromStdString (afl[i]));
+                       }
+
+                     emit request_add_octave_apis (api_entries);
+                   });
               }
             else
               {
-
-                m_prep_apis_file = prep_apis_path + lexer->lexer () + ".pap";
-
-                for (i=1; i<=3; i++) // test the first 5 keyword sets
+                for (int i = 1; i <= 3; i++)
                   {
-                    keyword = QString (lexer->keywords (i));           // get list
-                    keyword_list = keyword.split (QRegExp (R"(\s+)")); // split
-                    for (j = 0; j < keyword_list.size (); j++)         // add to API
+                    // Get list, split, and add to API.
+
+                    QString keyword = QString (lexer->keywords (i));
+
+                    QStringList keyword_list
+                      = keyword.split (QRegExp (R"(\s+)"));
+
+                    for (int j = 0; j < keyword_list.size (); j++)
                       m_lexer_apis->add (keyword_list.at (j));
                   }
+
+                emit api_entries_added ();
               }
-
-            // disconnect slot for saving prepared info if already connected
-            disconnect (m_lexer_apis, SIGNAL (apiPreparationFinished ()), nullptr, nullptr);
-            // check whether path for prepared info exists or can be created
-            if (QDir ("/").mkpath (prep_apis_path))
-              {
-                // path exists, apis info can be saved there
-                connect (m_lexer_apis, SIGNAL (apiPreparationFinished ()),
-                         this, SLOT (save_apis_info ()));
-              }
-
-            m_lexer_apis->prepare ();  // prepare apis info
-
           }
       }
 
@@ -869,15 +885,30 @@
       m_edit_area->setMarginWidth (2,0);
   }
 
-
   // function for adding entries to the octave lexer's APIs
-  void file_editor_tab::add_octave_apis (octave_value_list key_ovl)
+  void file_editor_tab::handle_add_octave_apis (const QStringList& api_entries)
+  {
+    for (int idx = 0; idx < api_entries.size (); idx++)
+      m_lexer_apis->add (api_entries.at (idx));
+
+    emit api_entries_added ();
+  }
+
+  void file_editor_tab::handle_api_entries_added (void)
   {
-    octave_value keys = key_ovl(0);
-    Cell key_list = keys.cell_value ();
-
-    for (int idx = 0; idx < key_list.numel (); idx++)
-      m_lexer_apis->add (QString (key_list.elem (idx).string_value ().data ()));
+    // disconnect slot for saving prepared info if already connected
+    disconnect (m_lexer_apis, SIGNAL (apiPreparationFinished ()),
+                nullptr, nullptr);
+
+    // check whether path for prepared info exists or can be created
+    if (QDir ("/").mkpath (m_prep_apis_path))
+      {
+        // path exists, apis info can be saved there
+        connect (m_lexer_apis, SIGNAL (apiPreparationFinished ()),
+                 this, SLOT (save_apis_info ()));
+      }
+
+    m_lexer_apis->prepare ();  // prepare apis info
   }
 
   void file_editor_tab::save_apis_info (void)