Author Topic: Hiccups while typing (continuation)  (Read 8542 times)

Offline Elena

  • Multiple posting newcomer
  • *
  • Posts: 60
Hiccups while typing (continuation)
« on: January 31, 2025, 07:50:04 pm »
Since some months (not sure from which NB the problem started, unfortunately) I noticed there are annoying hiccups while editing code in the main text editor. In the meantime I tried disabling the following (on suggestion):
-Browse Tracker plugin (this improved slowness overall a lot though)
-Thread Search plugin (this likely improved the hiccups but not completely)

In particular, I suspect they are related to a plugin whose name I ignore, which is responsible for those two choosers (pop-down menus) in the top bar, which show all symbols defined in the current code. In fact, I notice that when such hiccups occur, those two choosers are displayed ghosted (disabled) for a fraction of a second and then become enabled again.
Btw, which is the plugin responsible for those, so that I can try disabling it, to see if the hiccups disappear ?

Using latest NB, Win10 x64.
Thx

Offline Pecan

  • Plugin developer
  • Lives here!
  • ****
  • Posts: 2839
Re: Hiccups while typing (continuation)
« Reply #1 on: February 01, 2025, 12:13:30 am »
Well, I'm sorry that BrowseTracker is not working for you.
But I do not know what else I can do since I cannot re-create the slow down hiccups.

BTW, what kind of machine are you using?
Are you using a system with an Intel Celeron?

Regarding the plugins that use popup windows and show code selections would be CodeCompletion and clangd_client.

CodeCompletion and cland_client are multi-threaded and require heavy usage of the cpu. You might want to disable them and see what happens to the hiccups.
« Last Edit: February 01, 2025, 12:25:44 am by Pecan »

Offline Elena

  • Multiple posting newcomer
  • *
  • Posts: 60
Re: Hiccups while typing (continuation)
« Reply #2 on: February 01, 2025, 12:56:45 am »
Hi Pecan,
my PC is an Intel i7 8700K 3,7 GHz, a very fast machine.
As I said, those "hiccups" started at some point, I would say between last Spring and Summer, sadly I can't say for sure from which Nightly Build :( But everything was fine and smooth before that point !

The clangd client is already disabled.
As for the Browser Tracker, I was suggested here to disable it, by another user who experienced slowdowns by it on startup (but it was not responsible for the hiccups while typing).
As for the Thread Search (another thing which was suggested here) I disabled it but I don't think that helped with the hiccups.

I tired to disable the Code Completion, but it was NOT the culprit.

Those little hiccups are noticeable in particular while moving the cursor thru the text.

As I said, I think the culprit is the plugin responsible for showing those two choosers in the top bar, with all functions defined in the current code. But I don't know which plugin it is, so I cannot try disabling it...

Offline Pecan

  • Plugin developer
  • Lives here!
  • ****
  • Posts: 2839
Re: Hiccups while typing (continuation)
« Reply #3 on: February 01, 2025, 06:40:44 am »
... In fact, I notice that when such hiccups occur, those two choosers are displayed ghosted (disabled) for a fraction of a second and then become enabled again.
Btw, which is the plugin responsible for those, so that I can try disabling it, to see if the hiccups disappear ?

Using latest NB, Win10 x64.
Thx

I'm unclear about which "two choosers" you mean.
Are they one of the menu choices, or one of the icon choices? Do they have a name that pops up if you hover the mouse over them?

If we could get closer to which "choosers", we can get closer to the problem.

Are you just hovering over some variable in the text when it happens.
Could you give me a "1)do this" then "2)do that" type instructions to get a clearer picture in my old mind?
« Last Edit: February 01, 2025, 06:43:24 am by Pecan »

Offline Elena

  • Multiple posting newcomer
  • *
  • Posts: 60
Re: Hiccups while typing (continuation)
« Reply #4 on: February 01, 2025, 12:39:36 pm »
Hi Pecan, I am sorry if I really cannot be more accurate.
I have attached a screenshot of those I call "choosers", very sorry for not having a better name for them lol
Which plugin is responsible for them btw ?
Unfortunately there are not any definite actions I can suggest to reproduce the hiccups :(
But I notice clearly, when moving the cursor thru the text, or sometimes while typing, that often very short pauses occur, fractions of a second I mean, but are annoying and noticeable and can still be confusing if one types or edits quickly. And when this happens, for a very short time those two gadgets flash or kind of, like they becoming disabled and then enabled again, so I suspected it could be related.
Again, I started noticing this problem at some point last Summer.

Offline Pecan

  • Plugin developer
  • Lives here!
  • ****
  • Posts: 2839
Re: Hiccups while typing (continuation)
« Reply #5 on: February 01, 2025, 07:46:00 pm »
... for a very short time those two gadgets flash or kind of, like they becoming disabled and then enabled again, so I suspected it could be relatedT
Thanks for the screenshot
.
Those are the Scope and function/variable choice boxes for the plugin Code Completion.

Go to MainMenu>plugins>ManagePlugins  and disable the plugin "Code completion", restart CB, and see if the hiccups disappear.

If that eliminates the hiccups re-enable "Code completion" and restart CB.

Now go to MainMenu>settings>Editor>CodeCompletion> and disable "update parser when typing" check box. See the attached screenshot. Tell us if that eliminate the hiccups.

Also check (at bottom of Code completion settings) "Delay for Auto-kick-in when typing". Raise to at least 300 millisecs or until the hiccups disappear.

Look, also, at the second screenshot (Editor settings) and make sure the kick in for Code completion is set at (say around) 3 letters.
 
« Last Edit: February 01, 2025, 10:34:25 pm by Pecan »

Offline Elena

  • Multiple posting newcomer
  • *
  • Posts: 60
Re: Hiccups while typing (continuation)
« Reply #6 on: February 02, 2025, 09:01:36 pm »
Hi Pecan,  thanks for your support !
Disabling Update Parser When Typing seems to have fixed the hiccups !
Re: the other two settings suggested were already 300 ms and 3

Offline Elena

  • Multiple posting newcomer
  • *
  • Posts: 60
Re: Hiccups while typing (continuation)
« Reply #7 on: February 02, 2025, 11:10:50 pm »
Oh what's up, a bug ?
It seems that if I close C::B and I reopen it, the "Update parser when typing" setting gets enabled again ! Can you check ?
NB svn 13598

Offline Pecan

  • Plugin developer
  • Lives here!
  • ****
  • Posts: 2839
Re: Hiccups while typing (continuation)
« Reply #8 on: February 03, 2025, 06:44:06 pm »
Oh what's up, a bug ?
It seems that if I close C::B and I reopen it, the "Update parser when typing" setting gets enabled again ! Can you check ?
NB svn 13598

Yes, it's a bug. When CB is closed with a project active, a new setting of "Update parser..." will toggle itself.

When CB is closed with no project active, then "Update parser..." is changed,the "Update parser..." will hold.

So..., when I close all projects, change the "Update parser..." then close CB, the status of the check box will hold.

Weird !

Edit: 12:48 pm
When closing with no project open the CC parser is not involved.
When closing with a project open, the parser at 928 writes the value it was constructed with, not the updated value from the settings dialog.

cfg->Write(_T("/while_typing"), m_Options.whileTyping); //(ph 2025/02/03) wrong value when calledfrom ClassBrowser 245

Called from ClassBrowser 245: m_Parser->WriteOptions();
m_Options.whileTyping has the value before it was changed in settings dialog.

What I don't understand is why ClassBrowser has a stale value of the "Update parser..." value. In .conf it's named <WHILE_TYPING bool="0" />




« Last Edit: February 03, 2025, 10:05:08 pm by Pecan »

Offline ollydbg

  • Developer
  • Lives here!
  • *****
  • Posts: 6070
  • OpenCV and Robotics
    • Chinese OpenCV forum moderator
Re: Hiccups while typing (continuation)
« Reply #9 on: February 04, 2025, 03:32:55 am »
If I remember correctly, it is a known bug for a long time. But I nearly forgot the details.

I just remember that: Each Parser instance(for each cbp projects) has there own CodeCompletion options, and when you saved the CodeCompletion options, it is only for the active Parser instance. But if you don't have any cbp file opened, there is still a special hidden Parser instance created for "dummy cbp projects".
If some piece of memory should be reused, turn them to variables (or const variables).
If some piece of operations should be reused, turn them to functions.
If they happened together, then turn them to classes.

Offline ollydbg

  • Developer
  • Lives here!
  • *****
  • Posts: 6070
  • OpenCV and Robotics
    • Chinese OpenCV forum moderator
Re: Hiccups while typing (continuation)
« Reply #10 on: February 04, 2025, 07:20:29 am »
Code
// ----------------------------------------------------------------------------
void ClassBrowser::SetParser(ParserBase* parser)
// ----------------------------------------------------------------------------
{
    if (m_Parser == parser)
        return;

    m_Parser = parser;
    if (m_Parser)
    {
        const int sel = XRCCTRL(*this, "cmbView", wxChoice)->GetSelection();
        BrowserDisplayFilter filter = static_cast<BrowserDisplayFilter>(sel);
        if (!m_ParseManager->IsParserPerWorkspace() && filter == bdfWorkspace)
            filter = bdfProject;

        m_Parser->ClassBrowserOptions().displayFilter = filter;
        m_Parser->WriteOptions();
        UpdateClassBrowserView();
    }
    else
        CCLogger::Get()->DebugLog("SetParser: No parser available.");
}

It looks like the "last Parser's option" is written to the configure file.

So, can we add a check here in the line 245 of the file: plugins\codecompletion\classbrowser.cpp

I mean if it is a dummy parser(temp parser), we won't need to save the parser's option?

Because when a cbp project get closed, the dummy parser is always active, so the dummy parser's option is always saved when I close the C::B. (But this has some issue, when user open C::B without opening any cbp file, all the option is saved to dummy parser)

Another method is that we can copy the option of a closed project to the dummy parser's option, so that the dummy parser's option will be the same as the last cbp project's option when get closed.
If some piece of memory should be reused, turn them to variables (or const variables).
If some piece of operations should be reused, turn them to functions.
If they happened together, then turn them to classes.

Offline Elena

  • Multiple posting newcomer
  • *
  • Posts: 60
Re: Hiccups while typing (continuation)
« Reply #11 on: February 04, 2025, 03:03:16 pm »
For me, the only way for the option to stay un-checked is opening C::B with no projects, un-checking it, closing C::B. Every project opened then will maintain the setting.

Offline ollydbg

  • Developer
  • Lives here!
  • *****
  • Posts: 6070
  • OpenCV and Robotics
    • Chinese OpenCV forum moderator
Re: Hiccups while typing (continuation)
« Reply #12 on: February 04, 2025, 03:05:47 pm »
When the workspace get closed(in the workspace close event handler), the below function will be called:

Code
bool ParseManager::DeleteParser(cbProject* project)
{
    wxString prj = (project ? project->GetTitle() : _T("*NONE*"));

    ParserList::iterator it = m_ParserList.begin();
    if (!m_ParserPerWorkspace)
    {
        for (; it != m_ParserList.end(); ++it)
        {
            if (it->first == project)
                break;
        }
    }

    if (it == m_ParserList.end())
    {
        CCLogger::Get()->DebugLog(wxString::Format("ParseManager::DeleteParser: Parser does not exist for delete '%s'!", prj));
        return false;
    }

    bool removeProjectFromParser = false;
    if (m_ParserPerWorkspace)
        removeProjectFromParser = RemoveProjectFromParser(project);

    if (m_ParsedProjects.empty()) // this indicates we are in one parser per one project mode
    {
        wxString log(wxString::Format(_("ParseManager::DeleteParser: Deleting parser for project '%s'!"), prj));
        CCLogger::Get()->Log(log);
        CCLogger::Get()->DebugLog(log);

        // the logic here is : firstly delete the parser instance, then see whether we need an
        // active parser switch (call SetParser())
        delete it->second;

        // if the active parser is deleted, set the active parser to nullptr
        if (it->second == m_Parser)
        {
            m_Parser = nullptr;
            SetParser(m_TempParser); // Also updates class browser
        }

        m_ParserList.erase(it);

        return true;
    }

    if (removeProjectFromParser)
        return true;

    CCLogger::Get()->DebugLog(_T("ParseManager::DeleteParser: Deleting parser failed!"));
    return false;
}

Note that there is a line:

Code
SetParser(m_TempParser); // Also updates class browser

In this case, the dummy parser is set as the "active parser". So, in the final stage, this dummy parser's option will be saved to the config file, not the last active project in the workspace.

If some piece of memory should be reused, turn them to variables (or const variables).
If some piece of operations should be reused, turn them to functions.
If they happened together, then turn them to classes.

Offline Pecan

  • Plugin developer
  • Lives here!
  • ****
  • Posts: 2839
Re: Hiccups while typing (continuation)
« Reply #13 on: February 04, 2025, 06:23:41 pm »
@ ollydbg

I'll test out your suggestions today. Thanks.

I'll test with NO project, then one, then multiple projects and see if checking for the dummy (first) parser works.

Another thought might be to issue a shared event to tell all parsers to re-read (update its parser.options) if a user clicks OK in the CodeCompletion settings dialog.

I don't mean to create a new global event, but I know that an event using an XRCID("mySharedEventId") is possible if both sender and receiver use the same XRCID.
« Last Edit: February 04, 2025, 06:42:47 pm by Pecan »

Offline Pecan

  • Plugin developer
  • Lives here!
  • ****
  • Posts: 2839
Re: Hiccups while typing (continuation)
« Reply #14 on: February 04, 2025, 07:09:03 pm »
@ ollydbg

How about this idea.

The ccoptionsdlg can always record, in a global var, the address of the active parser that last updated the settings.

When the workspace is closed, if that var contains an address, that parser will be the only parser that is allows to update the .conf settings.

That way, any number of projects can be in the workspace, but only the last parser to update the settings can finally store them to the .conf .

Wouldn't that work for only one parser and also for multiple parsers?

If the global var is nullptr, ccoptionsdlg never got called to change any option, then we don't care about which parser updates the .conf .

ccoptionsdlg would only set the active parsers address in the global var, if the user clicked OK to dismiss the dialog.
I'm assuming that the dismiss dialog action (OK or Cancel) can be caught.
Else we'd have to find another way to determine that the user changed any option.

Edit: 10:35am
Got It. void CCOptionsDlg::OnApply() is only called when user clicks OK. I'm thinking that's the only place we need to set the global var with the active parser address.



Is all this true?
« Last Edit: February 04, 2025, 07:43:26 pm by Pecan »

Offline ollydbg

  • Developer
  • Lives here!
  • *****
  • Posts: 6070
  • OpenCV and Robotics
    • Chinese OpenCV forum moderator
Re: Hiccups while typing (continuation)
« Reply #15 on: February 05, 2025, 02:23:01 am »
Another thought might be to issue a shared event to tell all parsers to re-read (update its parser.options) if a user clicks OK in the CodeCompletion settings dialog.

I don't mean to create a new global event, but I know that an event using an XRCID("mySharedEventId") is possible if both sender and receiver use the same XRCID.

I can't understand the logic here. But generally, I think this should be done inside the code completion plugin or its base plugin class.

I think the current logic is:

1, When a parser instance becomes "active", its options will be also get active, and "saved to the configure file".
2, When there is NO cbp files opened, a dummy parser(temp parser) will active, it also has its own options.

Case 1:
When you open C::B, the dummy parser is active, when you modify the CC's option, it was modifying the dummy parser's option. When you close C::B, the last active Parser is the dummy parser, so it setting is in the configure file.

Case 2:
You have one cbp(projectA) file opened, and the active parser is the opened cbp. So, when you tweak its CC setting, the option of this parser changed and saved to the configure file. Now, you click the "close button" to close C::B, it just "close the workspace" first. And if all the cbp files get closed, the dummy project parser will set active. You see that when a parser is set active, its option will be saved to the configure file. So, projectA's CC option will be overwritten by the dummy project parser's option to the configure file.


I think the logic here is that every Parser instance could have different options.

EDIT:

I only debugged the above 2 Cases, and I don't debugged other cases, and I can't say much about other cases.
« Last Edit: February 05, 2025, 02:24:33 am by ollydbg »
If some piece of memory should be reused, turn them to variables (or const variables).
If some piece of operations should be reused, turn them to functions.
If they happened together, then turn them to classes.

Offline ollydbg

  • Developer
  • Lives here!
  • *****
  • Posts: 6070
  • OpenCV and Robotics
    • Chinese OpenCV forum moderator
Re: Hiccups while typing (continuation)
« Reply #16 on: February 05, 2025, 02:41:07 am »
@ ollydbg

How about this idea.

The ccoptionsdlg can always record, in a global var, the address of the active parser that last updated the settings.

When the workspace is closed, if that var contains an address, that parser will be the only parser that is allows to update the .conf settings.

That way, any number of projects can be in the workspace, but only the last parser to update the settings can finally store them to the .conf .

Wouldn't that work for only one parser and also for multiple parsers?

If the global var is nullptr, ccoptionsdlg never got called to change any option, then we don't care about which parser updates the .conf .

ccoptionsdlg would only set the active parsers address in the global var, if the user clicked OK to dismiss the dialog.
I'm assuming that the dismiss dialog action (OK or Cancel) can be caught.
Else we'd have to find another way to determine that the user changed any option.

Edit: 10:35am
Got It. void CCOptionsDlg::OnApply() is only called when user clicks OK. I'm thinking that's the only place we need to set the global var with the active parser address.

Is all this true?

Some concerns from my mind.

The CC options includes the options from the ccoptionsdlg, but it also includes the options from the classbrowser's GUI.

So, when I see inside the SetParser() function call, it will also save the active classbrowser's GUI setting to the configure file.

Also, if a Parser instance is deleted, the global var (pointer) still point to the deleted memory?

If some piece of memory should be reused, turn them to variables (or const variables).
If some piece of operations should be reused, turn them to functions.
If they happened together, then turn them to classes.

Offline Pecan

  • Plugin developer
  • Lives here!
  • ****
  • Posts: 2839
Re: Hiccups while typing (continuation)
« Reply #17 on: February 05, 2025, 04:38:09 am »
@ ollydbg

Would you try the following CC patch. It works well for me.

It simply remembers the project that applied an options change.
At WriteOptions() it only lets that project update the CC Options and .conf and makes the other projects refresh their cached options.

Patch is also attached to this msg.

Code
Index: ccoptionsdlg.cpp
===================================================================
--- ccoptionsdlg.cpp (revision 13609)
+++ ccoptionsdlg.cpp (working copy)
@@ -183,6 +183,10 @@
 
 void CCOptionsDlg::OnApply()
 {
+    //(ph 2025/02/04) // Set the project that changed the .conf data //(ph 2025/02/04)
+    cbProject* pProject = Manager::Get()->GetProjectManager()->GetActiveProject();
+    m_ParseManager->SetOptsChangerProject(pProject);
+
     ConfigManager* cfg = Manager::Get()->GetConfigManager(_T("code_completion"));
 
     // -----------------------------------------------------------------------
Index: parsemanager.h
===================================================================
--- parsemanager.h (revision 13609)
+++ parsemanager.h (working copy)
@@ -258,6 +258,9 @@
     void SetSymbolsWindowHasFocus(bool trueOrFalse){ m_SymbolsWindowHasFocus = trueOrFalse;}
     bool GetSymbolsWindowHasFocus(){return m_SymbolsWindowHasFocus;}
 
+    cbProject* GetOptsChangerProject(){ return m_pOptsChangerProject;} //(ph 2025/02/04)
+    void SetOptsChangerProject(cbProject* pProject){m_pOptsChangerProject = pProject;} //(ph 2025/02/04)
+
 protected:
     /** When a Parser is created, we need a full parsing stage including:
      * 1, parse the priority header files firstly.
@@ -527,6 +530,9 @@
     bool m_ClassBrowserViewIsStale = true;
     bool m_SymbolsWindowHasFocus = false;
 
+    //The last project to change the .conf file //(ph 2025/02/04)
+    cbProject* m_pOptsChangerProject = nullptr;
+
 };
 
 #endif // PARSEMANAGER_H
Index: parser/parser.cpp
===================================================================
--- parser/parser.cpp (revision 13609)
+++ parser/parser.cpp (working copy)
@@ -29,6 +29,7 @@
 
 #include <wx/tokenzr.h>
 #include <cbstyledtextctrl.h>
+#include "..\parsemanager.h" //(ph 2025/02/04)
 
 #include "parser.h"
 #include "parserthreadedtask.h"
@@ -921,6 +922,16 @@
 
 void Parser::WriteOptions()
 {
+    // If this project didn't change the options, then don't let it overwrite them. //(ph 2025/02/04)
+    cbProject* pActiveProject = Manager::Get()->GetProjectManager()->GetActiveProject();
+    ParseManager* pParseMgr = (ParseManager*)m_Parent;
+    cbProject* pOptsChangerProject = pParseMgr->GetOptsChangerProject();
+    if ( pActiveProject != pOptsChangerProject )
+    {
+        ReadOptions();  // force projects that did not change options to re-read them.
+        return;
+    }
+
     ConfigManager* cfg = Manager::Get()->GetConfigManager(_T("code_completion"));
 
     // Page "Code Completion"
Index: resources/manifest.xml
===================================================================
--- resources/manifest.xml (revision 13609)
+++ resources/manifest.xml (working copy)
@@ -3,7 +3,7 @@
     <SdkVersion major="1" minor="10" release="0" />
     <Plugin name="CodeCompletion">
         <Value title="Code completion" />
-        <Value version="1.0.5 24/01/29" />
+        <Value version="1.0.6(ph) 25/02/04" />
         <Value description="This plugin provides a symbols browser for your projects and code-completion inside the editor.
 
 

« Last Edit: February 05, 2025, 04:44:02 am by Pecan »

Offline stahta01

  • Lives here!
  • ****
  • Posts: 7721
    • My Best Post
Re: Hiccups while typing (continuation)
« Reply #18 on: February 05, 2025, 04:48:06 am »
@ ollydbg

Would you try the following CC patch. It works well for me.

It simply remembers the project that applied an options change.
At WriteOptions() it only lets that project update the CC Options and .conf and makes the other projects refresh their cached options.

Patch is also attached to this msg.

Code
Index: ccoptionsdlg.cpp
===================================================================
--- ccoptionsdlg.cpp (revision 13609)
+++ ccoptionsdlg.cpp (working copy)
@@ -183,6 +183,10 @@
 
 void CCOptionsDlg::OnApply()
 {
+    //(ph 2025/02/04) // Set the project that changed the .conf data //(ph 2025/02/04)
+    cbProject* pProject = Manager::Get()->GetProjectManager()->GetActiveProject();
+    m_ParseManager->SetOptsChangerProject(pProject);
+
     ConfigManager* cfg = Manager::Get()->GetConfigManager(_T("code_completion"));
 
     // -----------------------------------------------------------------------
Index: parsemanager.h
===================================================================
--- parsemanager.h (revision 13609)
+++ parsemanager.h (working copy)
@@ -258,6 +258,9 @@
     void SetSymbolsWindowHasFocus(bool trueOrFalse){ m_SymbolsWindowHasFocus = trueOrFalse;}
     bool GetSymbolsWindowHasFocus(){return m_SymbolsWindowHasFocus;}
 
+    cbProject* GetOptsChangerProject(){ return m_pOptsChangerProject;} //(ph 2025/02/04)
+    void SetOptsChangerProject(cbProject* pProject){m_pOptsChangerProject = pProject;} //(ph 2025/02/04)
+
 protected:
     /** When a Parser is created, we need a full parsing stage including:
      * 1, parse the priority header files firstly.
@@ -527,6 +530,9 @@
     bool m_ClassBrowserViewIsStale = true;
     bool m_SymbolsWindowHasFocus = false;
 
+    //The last project to change the .conf file //(ph 2025/02/04)
+    cbProject* m_pOptsChangerProject = nullptr;
+
 };
 
 #endif // PARSEMANAGER_H
Index: parser/parser.cpp
===================================================================
--- parser/parser.cpp (revision 13609)
+++ parser/parser.cpp (working copy)
@@ -29,6 +29,7 @@
 
 #include <wx/tokenzr.h>
 #include <cbstyledtextctrl.h>
+#include "..\parsemanager.h" //(ph 2025/02/04)
 
 #include "parser.h"
 #include "parserthreadedtask.h"
@@ -921,6 +922,16 @@
 
 void Parser::WriteOptions()
 {
+    // If this project didn't change the options, then don't let it overwrite them. //(ph 2025/02/04)
+    cbProject* pActiveProject = Manager::Get()->GetProjectManager()->GetActiveProject();
+    ParseManager* pParseMgr = (ParseManager*)m_Parent;
+    cbProject* pOptsChangerProject = pParseMgr->GetOptsChangerProject();
+    if ( pActiveProject != pOptsChangerProject )
+    {
+        ReadOptions();  // force projects that did not change options to re-read them.
+        return;
+    }
+
     ConfigManager* cfg = Manager::Get()->GetConfigManager(_T("code_completion"));
 
     // Page "Code Completion"
Index: resources/manifest.xml
===================================================================
--- resources/manifest.xml (revision 13609)
+++ resources/manifest.xml (working copy)
@@ -3,7 +3,7 @@
     <SdkVersion major="1" minor="10" release="0" />
     <Plugin name="CodeCompletion">
         <Value title="Code completion" />
-        <Value version="1.0.5 24/01/29" />
+        <Value version="1.0.6(ph) 25/02/04" />
         <Value description="This plugin provides a symbols browser for your projects and code-completion inside the editor.
 
 


Code
#include "..\parsemanager.h"

My guess is the above line will fail under Linux.

Tim S.
C Programmer working to learn more about C++ and Git.
On Windows 7 64 bit and Windows 10 64 bit.
--
When in doubt, read the CB WiKi FAQ. http://wiki.codeblocks.org

Offline Pecan

  • Plugin developer
  • Lives here!
  • ****
  • Posts: 2839
Re: Hiccups while typing (continuation)
« Reply #19 on: February 05, 2025, 06:37:57 am »


Code
#include "..\parsemanager.h"

My guess is the above line will fail under Linux.

Tim S.

Thanks

Offline ollydbg

  • Developer
  • Lives here!
  • *****
  • Posts: 6070
  • OpenCV and Robotics
    • Chinese OpenCV forum moderator
Re: Hiccups while typing (continuation)
« Reply #20 on: February 05, 2025, 09:42:56 am »
I'm not fully understand the patch, it looks like all the Parser instance will share the same "option".

If you set a breakpoint(BP) in the file: parser.cpp, in the function body: void Parser::WriteOptions()

Then do something like below:

1, start C::B, this will hit the BP
2, when you open a project, the BP will hit again, at this time, "ReadOptions()" will be called, and returned without writing to the configure file.
3, when you change the classbrowser's option, from current "project" to "everything", the BP will hit again, and "ReadOptions()" will be called again, but still not write to the configure file.

From my point of view, this is not correct.

As Tim said, we should use "../xxxxx.h" include directive, thanks.
If some piece of memory should be reused, turn them to variables (or const variables).
If some piece of operations should be reused, turn them to functions.
If they happened together, then turn them to classes.

Offline Pecan

  • Plugin developer
  • Lives here!
  • ****
  • Posts: 2839
Re: Hiccups while typing (continuation)
« Reply #21 on: February 05, 2025, 06:57:53 pm »
I'm not fully understand the patch, it looks like all the Parser instance will share the same "option".

If you set a breakpoint(BP) in the file: parser.cpp, in the function body: void Parser::WriteOptions()

Then do something like below:

1, start C::B, this will hit the BP
2, when you open a project, the BP will hit again, at this time, "ReadOptions()" will be called, and returned without writing to the configure file.
3, when you change the classbrowser's option, from current "project" to "everything", the BP will hit again, and "ReadOptions()" will be called again, but still not write to the configure file.

From my point of view, this is not correct.

As Tim said, we should use "../xxxxx.h" include directive, thanks.

I can't find a "Class browser's option. Where is that?
I can possible make those options "always write" if I could figure out where that is.

As it is with the patch:
If no changes were ever made to settings, why should anything be written to the .conf?

The write to .conf takes place when a user changes an item in MainMenu>settings>CodeCompletion.

@parser.cpp void Parser::WriteOptions()
WriteOptions take place on CB startup but changes nothing because active parser is null and m_pOptsChangerProject is null.

Any change made while no project is active gets written to .conf

When a project is loaded nothing has changed in .conf, so no write options need to be done.

If changes are made to settings (OnApply is entered), the active parser that made the changes
is recorded by OnApply().
Those changes are then written to the .conf, and only the settings made by that
active project are written to the .conf. all other projects read those settings.

If no user setting are made via settings, no need to care about writing the .conf.]
Code
ActiveProject   OnAppy project  ActiveProject != OnApplyProject     action
--------------  --------------  -------------------------------    ----------
nullptr          nullptr        False,  will write                  .conf written at startup
nullptr          nullptr        False,  will write                  no projects,.option changed, .conf wrtten
Nullptr          Not null       Does not happen                     Can't happen, no project to record
Not null         nullptr        True,   no write                    no setting changed, no writes
Not null         not null       False,  will write                  option changed, .conf written
nullptr          nullptr        False,  will write                  project closed but no options change, no write
nullptr          not null       True,   no write                    project closed, .conf written for matching project

Writes to the .conf take place only when there is no project or when a project changes options.
when a project changes options, only that project is allow to write the .conf
« Last Edit: February 05, 2025, 08:21:43 pm by Pecan »

Offline ollydbg

  • Developer
  • Lives here!
  • *****
  • Posts: 6070
  • OpenCV and Robotics
    • Chinese OpenCV forum moderator
Re: Hiccups while typing (continuation)
« Reply #22 on: February 06, 2025, 02:56:14 am »
I can't find a "Class browser's option. Where is that?
I can possible make those options "always write" if I could figure out where that is.

If you look at this function: void Parser::WriteOptions(), you will see that it actually save two member variables: one is the m_Options, and the other is the m_BrowserOptions.
In my mind, it looks like the "m_BrowserOptions" is shared by all the Parser instances. But the "m_Options" is not, so each Parser instance has its own "m_Options". So, switch the Parser won't switch the browser options, instead, it keep the browser options, but the "m_Options" need to be changed if different Parsers have different m_Options.

So, when a Parser is constructed, it first read the "m_BrowserOptions" and "m_Options" from the configure file, and later user can adjust its own options.

When we switch cbp in a workspace, one Parser get active, so its "m_Options" get active, at this time, the configure file is updated, I mean the active parser's "m_Options" is saved to the configure file.

But if you look at the function: void ClassBrowser::SetParser(ParserBase* parser), you will see:

Code
// ----------------------------------------------------------------------------
void ClassBrowser::SetParser(ParserBase* parser)
// ----------------------------------------------------------------------------
{
    if (m_Parser == parser)
        return;

    m_Parser = parser;
    if (m_Parser)
    {
        const int sel = XRCCTRL(*this, "cmbView", wxChoice)->GetSelection();
        BrowserDisplayFilter filter = static_cast<BrowserDisplayFilter>(sel);
        if (!m_ParseManager->IsParserPerWorkspace() && filter == bdfWorkspace)
            filter = bdfProject;

        m_Parser->ClassBrowserOptions().displayFilter = filter;
        m_Parser->WriteOptions();
        UpdateClassBrowserView();
    }
    else
        CCLogger::Get()->DebugLog("SetParser: No parser available.");
}

You see the "m_Parser->WriteOptions();" also get called.

So, maybe, it looks like we may need to call the "WriteClassBrowserOptions()" like function here inside the "void ClassBrowser::SetParser(ParserBase* parser)", because this class only response for the ClassBrowser related options.

If some piece of memory should be reused, turn them to variables (or const variables).
If some piece of operations should be reused, turn them to functions.
If they happened together, then turn them to classes.

Offline ollydbg

  • Developer
  • Lives here!
  • *****
  • Posts: 6070
  • OpenCV and Robotics
    • Chinese OpenCV forum moderator
Re: Hiccups while typing (continuation)
« Reply #23 on: February 06, 2025, 03:09:40 am »
Quote
Any change made while no project is active gets written to .conf

I agree, this include the m_Options and the m_BrowserOptions.

Quote
When a project is loaded nothing has changed in .conf, so no write options need to be done.

I agree.

Quote
If changes are made to settings (OnApply is entered), the active parser that made the changes is recorded by OnApply().
Those changes are then written to the .conf, and only the settings made by that active project are written to the .conf.
all other projects read those settings.

I agree that the writing of m_Options to the configure file should only happens inside the OnApply() function.
When user tweak the Class browser GUI options, it should always to saved to configure file.

But, I think the last sentence ("all other projects read those settings") is not correct. When we switch the Parser, the other Parser should read the m_BrowserOptions, because this is a global setting.
But we don't need to "re-read" the m_Options from the configure file, because different Parsers may have different parsing options.


Quote
If no user setting are made via settings, no need to care about writing the .conf.
I agree.
If some piece of memory should be reused, turn them to variables (or const variables).
If some piece of operations should be reused, turn them to functions.
If they happened together, then turn them to classes.

Offline Pecan

  • Plugin developer
  • Lives here!
  • ****
  • Posts: 2839
Re: Hiccups while typing (continuation)
« Reply #24 on: February 07, 2025, 09:43:47 pm »
@ ollydbg

Please evaluate this patch.
I've tested it with single and mult-project workspaces, Single file workspace and empty ones as well.

I think I've followed your outline (previous msg) to guard against stowing any stale global status while always allowing ClassBrowser status to be updated.


Code
Index: ccoptionsdlg.cpp
===================================================================
--- ccoptionsdlg.cpp (revision 13610)
+++ ccoptionsdlg.cpp (working copy)
@@ -183,6 +183,12 @@
 
 void CCOptionsDlg::OnApply()
 {
+    cbProject* pProject = Manager::Get()->GetProjectManager()->GetActiveProject();
+     // Remember the project that changed the .conf data //(ph 2025/02/04)
+    m_ParseManager->SetOptsChangedByProject(pProject);
+    // Renember the Parser that changed the .conf data //(ph 2025/02/04)
+    m_ParseManager->SetOptsChangedByParser(&(m_ParseManager->GetParser())); //(ph 2025/02/07)
+
     ConfigManager* cfg = Manager::Get()->GetConfigManager(_T("code_completion"));
 
     // -----------------------------------------------------------------------
Index: parsemanager.h
===================================================================
--- parsemanager.h (revision 13610)
+++ parsemanager.h (working copy)
@@ -9,8 +9,8 @@
 #include "parsemanager_base.h"
 #include "parser/parser.h"
 
-#include <queue>
-#include <map>
+//unused #include <queue>
+// unused #include <map>
 #include <memory>
 #include <unordered_map>
 
@@ -258,6 +258,14 @@
     void SetSymbolsWindowHasFocus(bool trueOrFalse){ m_SymbolsWindowHasFocus = trueOrFalse;}
     bool GetSymbolsWindowHasFocus(){return m_SymbolsWindowHasFocus;}
 
+    // Set or return Project that changed "Global setting" in workspace
+    cbProject* GetOptsChangedByProject(){ return m_pOptsChangedProject;}
+    void SetOptsChangedByProject(cbProject* pProject){m_pOptsChangedProject = pProject;}
+    // Set or return Parser that changed "Global setting" in Single File workspace
+    ParserBase* GetTempParser(){return m_TempParser;}
+    ParserBase* GetOptsChangedByParser(){ return m_pOptsChangedParser;}
+    void SetOptsChangedByParser(ParserBase* pParserBase){m_pOptsChangedParser = &(GetParser());}
+
 protected:
     /** When a Parser is created, we need a full parsing stage including:
      * 1, parse the priority header files firstly.
@@ -474,11 +482,12 @@
      */
     bool RemoveProjectFromParser(cbProject* project);
 
+
 private:
     typedef std::pair<cbProject*, ParserBase*> ProjectParserPair;
     typedef std::list<ProjectParserPair>       ParserList;
 
-    /** a list holing all the cbp->parser pairs, if in one parser per project mode, there are many
+    /** a list holding all the cbp->parser pairs, if in one parser per project mode, there are many
      * many pairs in this list. In one parser per workspace mode, there is only one pair, and the
      * m_ParserList.begin()->second is the common parser for all the projects in workspace.
      */
@@ -527,6 +536,11 @@
     bool m_ClassBrowserViewIsStale = true;
     bool m_SymbolsWindowHasFocus = false;
 
+    //The latest project to change the .conf file //(ph 2025/02/04)
+    cbProject* m_pOptsChangedProject = nullptr;
+    //The latest parser to change the .conf file //(ph 2025/02/04)
+    ParserBase* m_pOptsChangedParser = nullptr;
+
 };
 
 #endif // PARSEMANAGER_H
Index: parser/parser.cpp
===================================================================
--- parser/parser.cpp (revision 13610)
+++ parser/parser.cpp (working copy)
@@ -32,9 +32,10 @@
 
 #include "parser.h"
 #include "parserthreadedtask.h"
+#include "../parsemanager.h" //(ph 2025/02/04)
 
 #include "../classbrowser.h"
-#include "../classbrowserbuilderthread.h"
+//unused - #include "../classbrowserbuilderthread.h"
 
 
 #ifndef CB_PRECOMP
@@ -921,19 +922,59 @@
 
 void Parser::WriteOptions()
 {
+     //(ph 2025/02/06)
+    // Assemble status to determine if a Parser or Project changed a global setting.
+    ProjectManager* pPrjMgr = Manager::Get()->GetProjectManager();
+    cbProject*      pActiveProject = pPrjMgr->GetActiveProject();
+    ParseManager*   pParseMgr = (ParseManager*)m_Parent;
+    ParserBase*     pParser = &(pParseMgr->GetParser());
+    ParserBase*     pTempParser = pParseMgr->GetTempParser();
+    cbProject*      pOptsChangerProject = pParseMgr->GetOptsChangedByProject();
+
+    int  projectsCount = pPrjMgr->GetProjects()->size();
+    bool isTempParser  = (pParser == pTempParser);
+    bool globalOptionChanged = pParseMgr->GetOptsChangedByParser() or pParseMgr->GetOptsChangedByProject();
+
     ConfigManager* cfg = Manager::Get()->GetConfigManager(_T("code_completion"));
 
-    // Page "Code Completion"
-    cfg->Write(_T("/use_SmartSense"),                m_Options.useSmartSense);
-    cfg->Write(_T("/while_typing"),                  m_Options.whileTyping);
+    // **Debugging** use this global to verify logic
+    // bool parseWhileTypingStatus = m_Options.whileTyping;
 
-    // Page "C / C++ parser"
-    cfg->Write(_T("/parser_follow_local_includes"),  m_Options.followLocalIncludes);
-    cfg->Write(_T("/parser_follow_global_includes"), m_Options.followGlobalIncludes);
-    cfg->Write(_T("/want_preprocessor"),             m_Options.wantPreprocessor);
-    cfg->Write(_T("/parse_complex_macros"),          m_Options.parseComplexMacros);
-    cfg->Write(_T("/platform_check"),                m_Options.platformCheck);
+    // Do not allow stale parser settings to change the global settings
+    bool allowGlobalUpdate = false;
+    if ( (projectsCount == 0) and globalOptionChanged)
+        allowGlobalUpdate = true;   //Single file settings changes
+    if (projectsCount and (pOptsChangerProject == pActiveProject) )
+        allowGlobalUpdate = true;   // changes made by a project
+    if ( (projectsCount==0) and isTempParser and globalOptionChanged)
+        allowGlobalUpdate = false; // TempParser has stale settings on Close()
+    if (not globalOptionChanged)
+        allowGlobalUpdate = false; // no global settings have changed
 
+    if (allowGlobalUpdate)
+    {
+        // Page "Code Completion"
+        cfg->Write(_T("/use_SmartSense"),                m_Options.useSmartSense);
+        cfg->Write(_T("/while_typing"),                  m_Options.whileTyping);
+
+        // Page "C / C++ parser"
+        cfg->Write(_T("/parser_follow_local_includes"),  m_Options.followLocalIncludes);
+        cfg->Write(_T("/parser_follow_global_includes"), m_Options.followGlobalIncludes);
+        cfg->Write(_T("/want_preprocessor"),             m_Options.wantPreprocessor);
+        cfg->Write(_T("/parse_complex_macros"),          m_Options.parseComplexMacros);
+        cfg->Write(_T("/platform_check"),                m_Options.platformCheck);
+    }
+    if ((projectsCount == 0) and isTempParser and globalOptionChanged)
+    {
+        // When no projects exists but the CB main settings have been changed,
+        // force the TempParser to reread settings/options else stale ones
+        // will be displayed on the next use of MenuBar/Settings/Editor/CodeCompletion dialog
+        ReadOptions();
+        // The global settings changed status can now be reset
+        pParseMgr->SetOptsChangedByParser(nullptr);
+        pParseMgr->SetOptsChangedByProject(nullptr);
+    }
+
     // Page "Symbol browser"
     cfg->Write(_T("/browser_show_inheritance"),      m_BrowserOptions.showInheritance);
     cfg->Write(_T("/browser_expand_ns"),             m_BrowserOptions.expandNS);
Index: resources/manifest.xml
===================================================================
--- resources/manifest.xml (revision 13610)
+++ resources/manifest.xml (working copy)
@@ -3,7 +3,7 @@
     <SdkVersion major="1" minor="10" release="0" />
     <Plugin name="CodeCompletion">
         <Value title="Code completion" />
-        <Value version="1.0.5 24/01/29" />
+        <Value version="1.0.6 25/02/7" />
         <Value description="This plugin provides a symbols browser for your projects and code-completion inside the editor.
 
 

« Last Edit: February 07, 2025, 10:17:54 pm by Pecan »

Offline ollydbg

  • Developer
  • Lives here!
  • *****
  • Posts: 6070
  • OpenCV and Robotics
    • Chinese OpenCV forum moderator
Re: Hiccups while typing (continuation)
« Reply #25 on: February 08, 2025, 08:42:14 am »
Thanks for your work.

Quote
I've tested it with single and mult-project workspaces, Single file workspace and empty ones as well.

single project workspace: a workspace only has one project.
mult-project workspace: a workspace has many projects.
Single file workspace: a single Parser will hold all the tokens in the whole workspace, whenever the workspace has one projects or more projects.
empty: no workspace is opened, neither a project is opened, in this case, the temp parser instance will be used.

Am I correct about the above description?
If some piece of memory should be reused, turn them to variables (or const variables).
If some piece of operations should be reused, turn them to functions.
If they happened together, then turn them to classes.

Offline ollydbg

  • Developer
  • Lives here!
  • *****
  • Posts: 6070
  • OpenCV and Robotics
    • Chinese OpenCV forum moderator
Re: Hiccups while typing (continuation)
« Reply #26 on: February 08, 2025, 02:02:57 pm »
I debugged your patch, and I found it still has logic errors, here is my steps:

1, start the debuggee C::B
2, load a cbp file
3, change some CC setting(from the code completion plugin's setting dialog)
4, close the cbp
5, change some CC setting(from the code completion plugin's setting dialog)
6, exit the debugee C::B

Note that from my point of view, in step 5, when I open the CC setting dialog, and change some settings, when I close the dialog, I need to "Save the setting to the configure file).
But actually, it is NOT.

If some piece of memory should be reused, turn them to variables (or const variables).
If some piece of operations should be reused, turn them to functions.
If they happened together, then turn them to classes.

Offline Pecan

  • Plugin developer
  • Lives here!
  • ****
  • Posts: 2839
Re: Hiccups while typing (continuation)
« Reply #27 on: February 08, 2025, 05:29:25 pm »
I debugged your patch, and I found it still has logic errors, here is my steps:

1, start the debuggee C::B
2, load a cbp file
3, change some CC setting(from the code completion plugin's setting dialog)
4, close the cbp
5, change some CC setting(from the code completion plugin's setting dialog)
6, exit the debugee C::B

Note that from my point of view, in step 5, when I open the CC setting dialog, and change some settings, when I close the dialog, I need to "Save the setting to the configure file).
But actually, it is NOT.

It seems I'm not forcing TempParser to update soon enough.
This is just no fun. 8>{

Offline Pecan

  • Plugin developer
  • Lives here!
  • ****
  • Posts: 2839
Re: Hiccups while typing (continuation)
« Reply #28 on: February 09, 2025, 12:22:20 am »
@ ollydbg

Thanks for doing all this testing.
I moved the forced TempParse update to before the .conf write.
That seemed to do the trick.

When you get a chance, would you test to see if I'm doing any better. So far, I'm batting 0 for 5.

Code
Index: ccoptionsdlg.cpp
===================================================================
--- ccoptionsdlg.cpp (revision 13610)
+++ ccoptionsdlg.cpp (working copy)
@@ -183,6 +183,12 @@
 
 void CCOptionsDlg::OnApply()
 {
+    cbProject* pProject = Manager::Get()->GetProjectManager()->GetActiveProject();
+     // Remember the project that changed the .conf data //(ph 2025/02/04)
+    m_ParseManager->SetOptsChangedByProject(pProject);
+    // Renember the Parser that changed the .conf data //(ph 2025/02/04)
+    m_ParseManager->SetOptsChangedByParser(&(m_ParseManager->GetParser())); //(ph 2025/02/07)
+
     ConfigManager* cfg = Manager::Get()->GetConfigManager(_T("code_completion"));
 
     // -----------------------------------------------------------------------
Index: parsemanager.h
===================================================================
--- parsemanager.h (revision 13610)
+++ parsemanager.h (working copy)
@@ -9,8 +9,8 @@
 #include "parsemanager_base.h"
 #include "parser/parser.h"
 
-#include <queue>
-#include <map>
+//unused #include <queue>
+// unused #include <map>
 #include <memory>
 #include <unordered_map>
 
@@ -258,6 +258,14 @@
     void SetSymbolsWindowHasFocus(bool trueOrFalse){ m_SymbolsWindowHasFocus = trueOrFalse;}
     bool GetSymbolsWindowHasFocus(){return m_SymbolsWindowHasFocus;}
 
+    // Set or return Project that changed "Global setting" in workspace
+    cbProject* GetOptsChangedByProject(){ return m_pOptsChangedProject;}
+    void SetOptsChangedByProject(cbProject* pProject){m_pOptsChangedProject = pProject;}
+    // Set or return Parser that changed "Global setting" in Single File workspace
+    ParserBase* GetOptsChangedByParser(){ return m_pOptsChangedParser;}
+    void SetOptsChangedByParser(ParserBase* pParserBase){m_pOptsChangedParser = pParserBase;}
+    ParserBase* GetTempParser(){return m_TempParser;}
+
 protected:
     /** When a Parser is created, we need a full parsing stage including:
      * 1, parse the priority header files firstly.
@@ -474,11 +482,12 @@
      */
     bool RemoveProjectFromParser(cbProject* project);
 
+
 private:
     typedef std::pair<cbProject*, ParserBase*> ProjectParserPair;
     typedef std::list<ProjectParserPair>       ParserList;
 
-    /** a list holing all the cbp->parser pairs, if in one parser per project mode, there are many
+    /** a list holding all the cbp->parser pairs, if in one parser per project mode, there are many
      * many pairs in this list. In one parser per workspace mode, there is only one pair, and the
      * m_ParserList.begin()->second is the common parser for all the projects in workspace.
      */
@@ -527,6 +536,11 @@
     bool m_ClassBrowserViewIsStale = true;
     bool m_SymbolsWindowHasFocus = false;
 
+    //The latest project to change the .conf file //(ph 2025/02/04)
+    cbProject* m_pOptsChangedProject = nullptr;
+    //The latest parser to change the .conf file //(ph 2025/02/04)
+    ParserBase* m_pOptsChangedParser = nullptr;
+
 };
 
 #endif // PARSEMANAGER_H
Index: parser/parser.cpp
===================================================================
--- parser/parser.cpp (revision 13610)
+++ parser/parser.cpp (working copy)
@@ -32,9 +32,10 @@
 
 #include "parser.h"
 #include "parserthreadedtask.h"
+#include "../parsemanager.h" //(ph 2025/02/04)
 
 #include "../classbrowser.h"
-#include "../classbrowserbuilderthread.h"
+//unused - #include "../classbrowserbuilderthread.h"
 
 
 #ifndef CB_PRECOMP
@@ -921,19 +922,66 @@
 
 void Parser::WriteOptions()
 {
+     //(ph 2025/02/06) Global settings bug fix
+     //https://forums.codeblocks.org/index.php/topic,25955 Hiccups while typing
+    // Assemble status to check if a Parser or Project changed a global setting.
+    ProjectManager* pPrjMgr = Manager::Get()->GetProjectManager();
+    cbProject*      pActiveProject = pPrjMgr->GetActiveProject();
+    ParseManager*   pParseMgr = (ParseManager*)m_Parent;
+    ParserBase*     pParser = &(pParseMgr->GetParser());
+    ParserBase*     pTempParser = pParseMgr->GetTempParser();
+    cbProject*      pOptsChangerProject = pParseMgr->GetOptsChangedByProject();
+
+    int  projectsCount = pPrjMgr->GetProjects()->size();
+    bool isTempParser = pTempParser == pParser;
+    bool globalOptionChanged = pParseMgr->GetOptsChangedByParser() or pParseMgr->GetOptsChangedByProject();
+
     ConfigManager* cfg = Manager::Get()->GetConfigManager(_T("code_completion"));
 
-    // Page "Code Completion"
-    cfg->Write(_T("/use_SmartSense"),                m_Options.useSmartSense);
-    cfg->Write(_T("/while_typing"),                  m_Options.whileTyping);
+    // **Debugging** use this global to verify logic (cached values)
+    bool OldWhileTypingStatus = m_Options.whileTyping;
+    asm("nop"); // **Debugging** set brkpt here
 
-    // Page "C / C++ parser"
-    cfg->Write(_T("/parser_follow_local_includes"),  m_Options.followLocalIncludes);
-    cfg->Write(_T("/parser_follow_global_includes"), m_Options.followGlobalIncludes);
-    cfg->Write(_T("/want_preprocessor"),             m_Options.wantPreprocessor);
-    cfg->Write(_T("/parse_complex_macros"),          m_Options.parseComplexMacros);
-    cfg->Write(_T("/platform_check"),                m_Options.platformCheck);
+    // Do not allow stale parser settings to change the global settings
+    bool allowGlobalUpdate = false;
+    if ( (projectsCount == 0) and globalOptionChanged)
+        allowGlobalUpdate = true;   //Single file settings changes
+    if (projectsCount and (pOptsChangerProject == pActiveProject) )
+        allowGlobalUpdate = true;   // changes made by a project
+    if ( (projectsCount==0) and isTempParser and globalOptionChanged)
+    {
+        // When no projects exists but the CB main settings have been changed,
+        // force the TempParser to reread settings/options else stale ones
+        // will be set and displayed on the next use of MenuBar/Settings/Editor/CodeCompletion dialog
+        #warning CodeCompletion: Remove the **Debugging** statements before commiting
+        bool oldWhileTypingStatus = m_Options.whileTyping; // **Debugging** //(ph 2025/02/08)
+        ReadOptions();  //force TempParser to update its settings
+        bool actualWhileTypingStatus = m_Options.whileTyping; // **Debugging** //(ph 2025/02/08)
+        allowGlobalUpdate = true;
+    }
+    if (not globalOptionChanged)
+        allowGlobalUpdate = false; // no global settings have changed
 
+    if (allowGlobalUpdate)
+    {
+        // Page "Code Completion"
+        cfg->Write(_T("/use_SmartSense"),                m_Options.useSmartSense);
+        cfg->Write(_T("/while_typing"),                  m_Options.whileTyping);
+
+        // Page "C / C++ parser"
+        cfg->Write(_T("/parser_follow_local_includes"),  m_Options.followLocalIncludes);
+        cfg->Write(_T("/parser_follow_global_includes"), m_Options.followGlobalIncludes);
+        cfg->Write(_T("/want_preprocessor"),             m_Options.wantPreprocessor);
+        cfg->Write(_T("/parse_complex_macros"),          m_Options.parseComplexMacros);
+        cfg->Write(_T("/platform_check"),                m_Options.platformCheck);
+    }
+    if ((projectsCount == 0) and isTempParser and globalOptionChanged)
+    {
+        // The global settings changed status can now be reset
+        pParseMgr->SetOptsChangedByParser(nullptr);
+        pParseMgr->SetOptsChangedByProject(nullptr);
+    }
+
     // Page "Symbol browser"
     cfg->Write(_T("/browser_show_inheritance"),      m_BrowserOptions.showInheritance);
     cfg->Write(_T("/browser_expand_ns"),             m_BrowserOptions.expandNS);
Index: resources/manifest.xml
===================================================================
--- resources/manifest.xml (revision 13610)
+++ resources/manifest.xml (working copy)
@@ -3,7 +3,7 @@
     <SdkVersion major="1" minor="10" release="0" />
     <Plugin name="CodeCompletion">
         <Value title="Code completion" />
-        <Value version="1.0.5 24/01/29" />
+        <Value version="1.0.6 25/02/8" />
         <Value description="This plugin provides a symbols browser for your projects and code-completion inside the editor.
 
 


I'll remove all the "**debugging**" tags and statements before any commit.
« Last Edit: February 09, 2025, 12:28:21 am by Pecan »

Offline ollydbg

  • Developer
  • Lives here!
  • *****
  • Posts: 6070
  • OpenCV and Robotics
    • Chinese OpenCV forum moderator
Re: Hiccups while typing (continuation)
« Reply #29 on: February 09, 2025, 08:01:43 am »
@ ollydbg

Thanks for doing all this testing.
I moved the forced TempParse update to before the .conf write.
That seemed to do the trick.

When you get a chance, would you test to see if I'm doing any better. So far, I'm batting 0 for 5.
...
...
I'll remove all the "**debugging**" tags and statements before any commit.

Sorry, it looks like this patch still has some errors, here is the steps. You see, I don't load any cbp files, but just open the debugee C::B for testing.

1, start the debuggee C::B
2, change some CC setting(from the code completion plugin's setting dialog)
3, change some CC setting(from the code completion plugin's setting dialog)
4, exit the debugee C::B

It looks like when the setting dialog's OnApply() function get called for the TempParser, the below code will be called:

Code
    if ( (projectsCount==0) and isTempParser and globalOptionChanged)
    {
        // When no projects exists but the CB main settings have been changed,
        // force the TempParser to reread settings/options else stale ones
        // will be set and displayed on the next use of MenuBar/Settings/Editor/CodeCompletion dialog
        // #warning CodeCompletion: Remove the **Debugging** statements before commiting
        // bool oldWhileTypingStatus = m_Options.whileTyping; // **Debugging** //(ph 2025/02/08)
        ReadOptions();  //force TempParser to update its settings
        // bool actualWhileTypingStatus = m_Options.whileTyping; // **Debugging** //(ph 2025/02/08)
        allowGlobalUpdate = true;
    }

So, in the step 3, when I open the CC's setting dialog, I see the setting are not saved in the step2.

If some piece of memory should be reused, turn them to variables (or const variables).
If some piece of operations should be reused, turn them to functions.
If they happened together, then turn them to classes.

Offline Pecan

  • Plugin developer
  • Lives here!
  • ****
  • Posts: 2839
Re: Hiccups while typing (continuation)
« Reply #30 on: February 10, 2025, 08:25:46 pm »
@ ollydbg

I stopped overthinking this, simplified, and came up this the 7th inning. I think this is a homerun.
Give it a try. Thanks.

Code
Index: classbrowser.cpp
===================================================================
--- classbrowser.cpp (revision 13611)
+++ classbrowser.cpp (working copy)
@@ -46,7 +46,7 @@
 
 #include "parser/ccdebuginfo.h"
 
-#include <stack>
+//unused #include <stack>
 #include <chrono>
 
 #define CC_CLASS_BROWSER_DEBUG_OUTPUT 0
@@ -242,6 +242,9 @@
             filter = bdfProject;
 
         m_Parser->ClassBrowserOptions().displayFilter = filter;
+        // Update stale CB globals in TempParser before WriteOptions() //(ph 2025/02/10)
+        if (m_Parser == m_ParseManager->GetTempParser())
+            m_Parser->ReadOptions();
         m_Parser->WriteOptions();
         UpdateClassBrowserView();
     }
Index: parsemanager.h
===================================================================
--- parsemanager.h (revision 13611)
+++ parsemanager.h (working copy)
@@ -9,8 +9,8 @@
 #include "parsemanager_base.h"
 #include "parser/parser.h"
 
-#include <queue>
-#include <map>
+//unused #include <queue>
+// unused #include <map>
 #include <memory>
 #include <unordered_map>
 
@@ -257,6 +257,7 @@
     //(ph 2024/01/25)
     void SetSymbolsWindowHasFocus(bool trueOrFalse){ m_SymbolsWindowHasFocus = trueOrFalse;}
     bool GetSymbolsWindowHasFocus(){return m_SymbolsWindowHasFocus;}
+    ParserBase* GetTempParser(){return m_TempParser;} //(ph 2025/02/10)
 
 protected:
     /** When a Parser is created, we need a full parsing stage including:
Index: resources/manifest.xml
===================================================================
--- resources/manifest.xml (revision 13611)
+++ resources/manifest.xml (working copy)
@@ -3,7 +3,7 @@
     <SdkVersion major="1" minor="10" release="0" />
     <Plugin name="CodeCompletion">
         <Value title="Code completion" />
-        <Value version="1.0.5 24/01/29" />
+        <Value version="1.0.6 25/02/10" />
         <Value description="This plugin provides a symbols browser for your projects and code-completion inside the editor.
 
 


Offline ollydbg

  • Developer
  • Lives here!
  • *****
  • Posts: 6070
  • OpenCV and Robotics
    • Chinese OpenCV forum moderator
Re: Hiccups while typing (continuation)
« Reply #31 on: February 12, 2025, 03:03:06 am »
Hi, Pecan, thanks for your hard work!
I debugged your patch yesterday. I think this patch is simple, but it still has some errors. Let me describe the issue again. I think in our code, we just "write" or "read" from the .conf file too much. I think every Parser instance's option is valid, so I don't think there is some "stale" option.

The problem is that we have several Parser instances. For example, we have ParserA, ParserB, ParserTemp. When there is no cbp opened, the ParserTemp always exists. I think when every Parser instance get constructed, it will "read" the options from the .conf file, that's OK.


Code
                                  +----------+     
         +------------------------|Parser A  |     
         |                        +----------+     
 +-------|------+                                 
 |Parse option  |                 +----------+     
 |Browser option|-----------------|Parser B  |     
 +-------|------+                 +----------+     
         |                                         
         |                        +-----------+   
         +------------------------|Parser Temp|   
                                  +-----------+   

1, When the Parser object get constructed, all the option should be copied from the .conf file to the object.

2, When the user open a editor->CodeCompletion option dialog, and edit some options, and click the "OK" button (in the OnApply function), I think all the options will be saved.

3, When we switch the Parser object(for example, the active project is switched from A to B, or from A to Temp), when switching, we don't need to "read all the options from the .conf file", because different Parser maintain its own option.

4, When user tweak the ClassBrowser option, I think it should save to the .conf file immediately after changing the ClassBrowser option.

5, When a Parser get closed, I think we don't need to "save" its option to the .conf file", because those options were either saved in the above "2" and "4" steps.

If some piece of memory should be reused, turn them to variables (or const variables).
If some piece of operations should be reused, turn them to functions.
If they happened together, then turn them to classes.

Offline Pecan

  • Plugin developer
  • Lives here!
  • ****
  • Posts: 2839
Re: Hiccups while typing (continuation)
« Reply #32 on: February 12, 2025, 10:42:35 pm »
@ ollydbg

Thanks for the clarity of that last message.
Here's the result of the re-work. For CB global settings:
1) write changes to .conf when user makes a change.
2) Do not write CB globals when closing a single file or when a parser is closing.
3) The TempParser must be updated when all parsers are closed else it writes its stale global settings (when CodeCompletion plugin initialized) to the .conf .

Code
Index: ccoptionsdlg.cpp
===================================================================
--- ccoptionsdlg.cpp (revision 13611)
+++ ccoptionsdlg.cpp (working copy)
@@ -183,6 +183,12 @@
 
 void CCOptionsDlg::OnApply()
 {
+    cbProject* pProject = Manager::Get()->GetProjectManager()->GetActiveProject();
+     // Remember the project that changed the .conf data //(ph 2025/02/04)
+    m_ParseManager->SetOptsChangedByProject(pProject);
+    // Renember the Parser that changed the .conf data //(ph 2025/02/04)
+    m_ParseManager->SetOptsChangedByParser(&(m_ParseManager->GetParser())); //(ph 2025/02/07)
+
     ConfigManager* cfg = Manager::Get()->GetConfigManager(_T("code_completion"));
 
     // -----------------------------------------------------------------------
Index: parsemanager.cpp
===================================================================
--- parsemanager.cpp (revision 13611)
+++ parsemanager.cpp (working copy)
@@ -623,6 +623,7 @@
         // if the active parser is deleted, set the active parser to nullptr
         if (it->second == m_Parser)
         {
+            SetClosingParser(m_Parser); //(ph 2025/02/12)
             m_Parser = nullptr;
             SetParser(m_TempParser); // Also updates class browser
         }
Index: parsemanager.h
===================================================================
--- parsemanager.h (revision 13611)
+++ parsemanager.h (working copy)
@@ -9,8 +9,8 @@
 #include "parsemanager_base.h"
 #include "parser/parser.h"
 
-#include <queue>
-#include <map>
+//unused #include <queue>
+// unused #include <map>
 #include <memory>
 #include <unordered_map>
 
@@ -258,6 +258,16 @@
     void SetSymbolsWindowHasFocus(bool trueOrFalse){ m_SymbolsWindowHasFocus = trueOrFalse;}
     bool GetSymbolsWindowHasFocus(){return m_SymbolsWindowHasFocus;}
 
+    // Set or return Project that changed "Global setting" in workspace
+    cbProject* GetOptsChangedByProject(){ return m_pOptsChangedProject;}
+    void SetOptsChangedByProject(cbProject* pProject){m_pOptsChangedProject = pProject;}
+    // Set or return Parser that changed "Global setting" in Single File workspace
+    ParserBase* GetOptsChangedByParser(){ return m_pOptsChangedParser;}
+    void SetOptsChangedByParser(ParserBase* pParserBase){m_pOptsChangedParser = pParserBase;}
+    ParserBase* GetTempParser(){return m_TempParser;}
+    ParserBase* GetClosingParser(){return m_pClosingParser;} //(ph 2025/02/12)
+    void        SetClosingParser(ParserBase* pParser){m_pClosingParser = pParser;} //(ph 2025/02/12)
+
 protected:
     /** When a Parser is created, we need a full parsing stage including:
      * 1, parse the priority header files firstly.
@@ -474,11 +484,12 @@
      */
     bool RemoveProjectFromParser(cbProject* project);
 
+
 private:
     typedef std::pair<cbProject*, ParserBase*> ProjectParserPair;
     typedef std::list<ProjectParserPair>       ParserList;
 
-    /** a list holing all the cbp->parser pairs, if in one parser per project mode, there are many
+    /** a list holding all the cbp->parser pairs, if in one parser per project mode, there are many
      * many pairs in this list. In one parser per workspace mode, there is only one pair, and the
      * m_ParserList.begin()->second is the common parser for all the projects in workspace.
      */
@@ -527,6 +538,13 @@
     bool m_ClassBrowserViewIsStale = true;
     bool m_SymbolsWindowHasFocus = false;
 
+    //The latest project to change the .conf file //(ph 2025/02/04)
+    cbProject* m_pOptsChangedProject = nullptr;
+    //The latest parser to change the .conf file //(ph 2025/02/04)
+    ParserBase* m_pOptsChangedParser = nullptr;
+    // the currently closing parser
+    ParserBase* m_pClosingParser = nullptr;
+
 };
 
 #endif // PARSEMANAGER_H
Index: parser/parser.cpp
===================================================================
--- parser/parser.cpp (revision 13611)
+++ parser/parser.cpp (working copy)
@@ -32,9 +32,10 @@
 
 #include "parser.h"
 #include "parserthreadedtask.h"
+#include "../parsemanager.h" //(ph 2025/02/04)
 
 #include "../classbrowser.h"
-#include "../classbrowserbuilderthread.h"
+//unused - #include "../classbrowserbuilderthread.h"
 
 
 #ifndef CB_PRECOMP
@@ -921,19 +922,64 @@
 
 void Parser::WriteOptions()
 {
+     // Global settings bug fix (ph 2025/02/12)
+     //https://forums.codeblocks.org/index.php/topic,25955 Hiccups while typing
+
+    // Assemble status to determine if a Parser or Project changed a global setting.
+    ParseManager*   pParseMgr = (ParseManager*)m_Parent;
+    ParserBase*     pTempParser = pParseMgr->GetTempParser();
+    ParserBase*     pClosingParser = pParseMgr->GetClosingParser(); //see ParseManger::DeleteParser()
+    ParserBase*     pCurrentParser = &(pParseMgr->GetParser());     //aka: m_parser
+
+    bool isClosingParser  = pCurrentParser == pClosingParser;
+    bool isTempParser     = pTempParser == pCurrentParser;
+    bool globalOptionChanged = pParseMgr->GetOptsChangedByParser() or pParseMgr->GetOptsChangedByProject();
+
+    // If this is a parser close, do not allow CB global settings writes.
+    bool allowGlobalUpdate = false;
+
+    // When no closing parser, but CB globals were changed, write to .conf
+    if ( (not isClosingParser) and globalOptionChanged)
+        allowGlobalUpdate = true;
+
+    // Closing parsers are not allowed to write to CB globals.
+    //  CB Globals were already written when when user changed the setting.
+    if (isClosingParser) allowGlobalUpdate = false;
+    // If no changes to the CB globals, no need to write
+    if (not globalOptionChanged)
+        allowGlobalUpdate = false; // no global settings have changed
+
     ConfigManager* cfg = Manager::Get()->GetConfigManager(_T("code_completion"));
 
-    // Page "Code Completion"
-    cfg->Write(_T("/use_SmartSense"),                m_Options.useSmartSense);
-    cfg->Write(_T("/while_typing"),                  m_Options.whileTyping);
+    // ----------------------------------------------------------------------------
+    // set any user changed CB global settings for CodeCompletion
+    // ----------------------------------------------------------------------------
+    if (allowGlobalUpdate)
+    {
+        // Page "Code Completion"
+        cfg->Write(_T("/use_SmartSense"),                m_Options.useSmartSense);
+        cfg->Write(_T("/while_typing"),                  m_Options.whileTyping);
 
-    // Page "C / C++ parser"
-    cfg->Write(_T("/parser_follow_local_includes"),  m_Options.followLocalIncludes);
-    cfg->Write(_T("/parser_follow_global_includes"), m_Options.followGlobalIncludes);
-    cfg->Write(_T("/want_preprocessor"),             m_Options.wantPreprocessor);
-    cfg->Write(_T("/parse_complex_macros"),          m_Options.parseComplexMacros);
-    cfg->Write(_T("/platform_check"),                m_Options.platformCheck);
+        // Page "C / C++ parser"
+        cfg->Write(_T("/parser_follow_local_includes"),  m_Options.followLocalIncludes);
+        cfg->Write(_T("/parser_follow_global_includes"), m_Options.followGlobalIncludes);
+        cfg->Write(_T("/want_preprocessor"),             m_Options.wantPreprocessor);
+        cfg->Write(_T("/parse_complex_macros"),          m_Options.parseComplexMacros);
+        cfg->Write(_T("/platform_check"),                m_Options.platformCheck);
 
+    }
+    // clean out any parser flags used to guard CB global settings
+    pParseMgr->SetOptsChangedByParser(nullptr);  //(ph 2025/02/12)
+    pParseMgr->SetOptsChangedByProject(nullptr); //(ph 2025/02/12)
+    pParseMgr->SetClosingParser(nullptr);
+    // if currrent parser == TempParser, force it to update, else the next
+    // display of the setting dialog will show TempParser stale cached settings.
+    if (isTempParser) pTempParser->ReadOptions();
+
+    // ----------------------------------------------------------------------------
+    // set any user changed ClassBrowser settings
+    // ----------------------------------------------------------------------------
+
     // Page "Symbol browser"
     cfg->Write(_T("/browser_show_inheritance"),      m_BrowserOptions.showInheritance);
     cfg->Write(_T("/browser_expand_ns"),             m_BrowserOptions.expandNS);
Index: resources/manifest.xml
===================================================================
--- resources/manifest.xml (revision 13611)
+++ resources/manifest.xml (working copy)
@@ -3,7 +3,7 @@
     <SdkVersion major="1" minor="10" release="0" />
     <Plugin name="CodeCompletion">
         <Value title="Code completion" />
-        <Value version="1.0.5 24/01/29" />
+        <Value version="1.0.6 25/02/12" />
         <Value description="This plugin provides a symbols browser for your projects and code-completion inside the editor.
 
 


Offline ollydbg

  • Developer
  • Lives here!
  • *****
  • Posts: 6070
  • OpenCV and Robotics
    • Chinese OpenCV forum moderator
Re: Hiccups while typing (continuation)
« Reply #33 on: February 13, 2025, 07:41:00 am »
Hi, thanks for your work.

I tested this patch. One issue I see is:

when I have projectA loaded, and later projectB loaded. Now, if I active projectB active, and I open the CC setting(option) dialog, change some settings, and click the apply button, the settings were saved to the .conf file. In this time, the ParserA and ParserB actually have different Parser settings. Now, if I switch the active Parser to projectA, and if I open the CC option dialog again, the setting is the new modified projectB's CC settings. Suppose in this case, the ParserA already finished its parsing, and its Parsing option is not the options when you see in the CC setting dialog.

So, what is the time we need to "read the Parser option from the .conf to the Parser instance", I think it should be in the constructor, and this should be the only place a Parser instance to read the initial parsing option.

Another thing I see which may be not correct (in the old code, not in your patch) is in this function:

Code
// ----------------------------------------------------------------------------
void ClassBrowser::SetParser(ParserBase* parser)
// ----------------------------------------------------------------------------
{
    if (m_Parser == parser)
        return;

    m_Parser = parser;
    if (m_Parser)
    {
        const int sel = XRCCTRL(*this, "cmbView", wxChoice)->GetSelection();
        BrowserDisplayFilter filter = static_cast<BrowserDisplayFilter>(sel);
        if (!m_ParseManager->IsParserPerWorkspace() && filter == bdfWorkspace)
            filter = bdfProject;

        m_Parser->ClassBrowserOptions().displayFilter = filter;
        m_Parser->WriteOptions();
        UpdateClassBrowserView();
    }
    else
        CCLogger::Get()->DebugLog("SetParser: No parser available.");
}

When we switch the Parser in the class browser, why do we need to "WriteOptions()"? I think we should only call something like "WriteClassBrowserOptions()", because I think switch the Parser only need to write the ClassBrowserOptions to the .conf file, but not the whole Parser options.

« Last Edit: February 13, 2025, 07:44:34 am by ollydbg »
If some piece of memory should be reused, turn them to variables (or const variables).
If some piece of operations should be reused, turn them to functions.
If they happened together, then turn them to classes.

Offline Pecan

  • Plugin developer
  • Lives here!
  • ****
  • Posts: 2839
Re: Hiccups while typing (continuation)
« Reply #34 on: February 13, 2025, 11:02:15 pm »
So, what is the time we need to "read the Parser option from the .conf to the Parser instance", I think it should be in the constructor, and this should be the only place a Parser instance to read the initial parsing option.

I don't understand this request at all.
 
If a parser only reads the settings at parser creation time, when the user later changes the global settings but the parser is not allowed to read them after the change, the user now is parsing without the settings he/she requested.

If that user was me, I'd call that a bug.

I think it would be better to throw up a message box saying "Sorry, sniff, global settings will not be applied for a project/parser until you request a re-parse of all the other loaded projects." Just kidding...

This is a hard problem. If we don't apply changes, we violate UI standards. If we do change them, a busy parser won't apply them anyway.

Maybe we should put up a message box that says, these changes will only be applied on the next re-parse for a project.
We could list the projects that have a 'busy' not done flag.

I remember this situation from about 13 years ago. The client asked me to throw up a message box that said "Options cannot be changed while a workspace is loaded".
« Last Edit: February 13, 2025, 11:33:16 pm by Pecan »

Offline ollydbg

  • Developer
  • Lives here!
  • *****
  • Posts: 6070
  • OpenCV and Robotics
    • Chinese OpenCV forum moderator
Re: Hiccups while typing (continuation)
« Reply #35 on: Yesterday at 03:50:37 am »
If a parser only reads the settings at parser creation time, when the user later changes the global settings but the parser is not allowed to read them after the change, the user now is parsing without the settings he/she requested.

If that user was me, I'd call that a bug.

My initial thought is that:

When user loads a cbp, the Parser created, and the global CC option is copied to the Parser's member variable(m_Options or other names). A TempParser is created when CC plugin get initialized, this Parser serves for the standalone cpp files parsing.

When project A's CC option dialog get opened, it shows the Parser A's member variable m_Options, and when user click the Apply button, its m_Options are updated, and the global options inside .conf file also get updated.

When we switch to project B, when I open the CC option dialog, it would show:

option1: Parser B's m_Options, because m_Options in Parser B is originally a copy of .conf when it gets created, so it is before we modify the "project A's CC options".

option2: Parser B's m_Options should reread from the .conf file, so that the global CC option was copied to project B.

From your point of view, you think the "option2" is the correct option. I just think a while, and I think you are correct, that is "All the Parser instances now share a same CC options".

Quote
I think it would be better to throw up a message box saying "Sorry, sniff, global settings will not be applied for a project/parser until you request a re-parse of all the other loaded projects." Just kidding...

This is a hard problem. If we don't apply changes, we violate UI standards. If we do change them, a busy parser won't apply them anyway.

Maybe we should put up a message box that says, these changes will only be applied on the next re-parse for a project.
We could list the projects that have a 'busy' not done flag.

I remember this situation from about 13 years ago. The client asked me to throw up a message box that said "Options cannot be changed while a workspace is loaded".

Yes, I agree. Changing some of the parsing option does not take effect immediately.

Even I have change the project A's CC option, and the parser A is already finished its parsing job, so to make the parser option get affect, we have to "reparse" the project.

As a convolution, I think you patch is OK! Thanks for so many times to tweak your patches.

The remaining issue is: since all the Parsers were sharing a single CC option, why do we keep so many copies? Maybe, we can just have one in the ParseManager class.  :)
If some piece of memory should be reused, turn them to variables (or const variables).
If some piece of operations should be reused, turn them to functions.
If they happened together, then turn them to classes.