Basic IDE Complete Journey

How not to approach the problem is the way :)

PROGRAMMINGOPEN-SOURCE

Devansh Varshney

10/20/202534 min read

Basic IDE Object Browser & Code Auto-completion

Mentors - Jonathan Clark, Prof. Rafael Lima, & Hossein

Last year I did the Google Summer of Code for LibreOffice regarding Adding the Native Support for the Histogram Chart and its Variations but somewhere I still felt that I lack enough skills to be able to do work independently.

So, this year I again asked that I really liked contributing here so this year I was also given the opportunity to not just contribute something important but also able to improve my skills to be able to surf(deep dive) the code-base independently.

This year this entire project was all about bringing the reliable dot(.) and Ctrl+Space code-auto completion in the LO Basic IDE just like how modern IDEs have and a good Object Browser to explore and see the APIs and Macros details.

Project Link - https://summerofcode.withgoogle.com/programs/2025/projects/iLT9BxsA

I have tried to put the development journey how it went from being a complicated bugified approach to refinement of the chronological breakdown of the final patches.


These weekly mails consist of how the development evolved and the final approved approaches are presented after these weekly mails.

Week 1-3: Jumping straight to code.

The beginning of this project started with me jumping straight to write the code and that was a rookie approach.
When I had my first meeting with my mentors there I had an "aha" moment when they said before we do anything we should be first assessing where we have what? form where we can get what? if we can access it how can we then able to access it? And if we are able to access it then how are we going to store it? And how currently our code-base is processing these information for example LibreOffice generates Doxygen API documentation, idl files are there how are these processed, ScriptForge, and so on.

Basically, the overall goal for the initial part of the project was to make a sort of an inventory -

So the month of May mostly went in exploring and building the Master Information table -
https://docs.google.com/spreadsheets/d/1t5wp6QO1YHEZB6QihkFyqdTGpvZ6yyKzT8HEtJVppsw/edit?usp=sharing

and here is also a document I prepared for the understanding of the Basic and Basctl directory -
https://drive.google.com/file/d/1zxf0FyRdMxfG4jrk3e6Lk-iby9wh3fOO/view?usp=sharing

It not just involved finding and exploring it also included to compare different ways of getting information. Looking at how Microsoft VBA presents its own API information browser.

Investigating the UNO API & Basic Macors Data Sources

The UNO API is vast, and understanding its structure was the biggest challenge.

  1. IDL (Interface Definition Language) Files: These text files are the ultimate source of truth, defining every UNO service, interface, and struct.

  2. RDB (Registry Database) Files: During the build process, the .idl files are compiled into optimized binary .rdb files (e.g., types.rdb, services.rdb).

  3. theCoreReflection Service: This was the most significant discovery. At runtime, LibreOffice exposes a powerful C++ service, com.sun.star.reflection.theCoreReflection, which provides live, programmatic access to all the type information loaded from the RDBs.

Parallel to the UNO investigation, I explored how to get information about both built-in BASIC functions and user-written code.

  1. BasicManager / StarBASIC: These core objects were identified as the runtime managers for all loaded BASIC libraries .xlb (library descriptor) and .xba (module) files.

  2. SbiParser / SbiSymPool: SbiParser is the BASIC language parser that analyzes BASIC source code and builds an internal representation. SbiSymPool is the symbol table that stores all identifiers (variables, functions, constants) discovered during parsing.

    The SbiParser/SbiSymPool system is the BASIC equivalent of what theCoreReflection provides for UNO types it gives you introspection capabilities for BASIC code. The key difference is that BASIC symbols are discovered through parsing source code, while UNO types are loaded from pre-compiled RDB files.

  3. ScriptForge: We analyzed the ScriptForge libraries as a model for a modern, complex BASIC library, uses Python .pyi stub file to provide type hints for external tools—a key inspiration for our project.

Here are the weekly mails for this work -

Week 1: https://lists.freedesktop.org/archives/libreoffice/2025-May/093264.html

Week 2 & 3: https://lists.freedesktop.org/archives/libreoffice/2025-June/093362.html

Week 4: After these findings what next?

So after being able to see where what we have the next step was to find a way we can access these UNO API and Application Macros details and see what amount of time it is taking for us to fetch all these details. The idea was create some Proof of Concepts(PoCs) focused on answering one question: is live data fetching fast enough for an interactive tool?

Week 4: https://lists.freedesktop.org/archives/libreoffice/2025-June/093392.html

This week 4 was one of the crucial point in this project where I started by trying to use the regview tool, but quickly hit a wall. It was here that the community's guidance proved invaluable. A timely question from Régis Perdreau about the relevance of the older idlc and regmerge tools, followed by a detailed explanation from Stephan Bergmann, illuminated the entire history of the UNO toolchain. I learned that regview was a legacy tool and that the modern equivalent is unoidl-read.

This interaction was a perfect example of the GSoC experience: learning not just the "what" but the "why" behind the codebase's history.

While unoidl-read itself would not be used in the final application, this PoC was vital. It proved that the .rdb files contained all the necessary information and provided a static dump file that could be used to validate the results of our live C++ PoCs.

And here is the entire week 4 mail thread (sorted according to thread): https://lists.freedesktop.org/archives/libreoffice/2025-June/thread.html

The Power of Live Introspection (theCoreReflection)

This was the most critical PoC, as it tested the exact C++ mechanism that would power the final IdeDataProvider. The goal was to query the live, in-memory UNO type system.

  1. Getting the Context: The first step was getting the process component context, the entry point to all live UNO services.

  2. Accessing theCoreReflection: We then programmatically accessed the com.sun.star.reflection.theCoreReflection singleton service.

  3. Introspecting a Type: The core of the PoC was using the forName() method to retrieve the XIdlClass interface for a specific type (e.g., com.sun.star.sheet.XSpreadsheet). This object acts as a "blueprint" for the type.

  4. Extracting Rich Details: By iterating through the XIdlClass methods and fields, the PoC successfully extracted and dumped the rich details needed for modern IDE features:

  • Method names and their fully-qualified return types.

  • Parameter names, types, and direction (in/out)—crucial for parameter-hint tooltips.

  • Inherited superclasses, necessary for a complete list of members.

and here are PoCs which we implemented: https://gerrit.libreoffice.org/c/core/+/186475
and its result- https://gerrit.libreoffice.org/c/core/+/186475/4/basic/uno_available_services_cpp_dump.txt

Week 5: Bringing Object Browser to Life

After getting a reasonably good performance the next directive from the mentors was to lets try to get this data live in the UI. Why live? The reasoning was since the response was good enough it would be better to see how it performs when we try to bring this to UI. Which will help us to strategies our direction for whether we have to store it like caching? or some other binary file structure? Basically, do we need to process this API information somewhere earlier or can we fetch this each time we open the BASIC IDE.

This meant diving deep into the SFX (StarView Framework)(Sfx2 module) command system, an intricate but powerful part of the LibreOffice core.

  1. My first attempt to register the new command for the Object Browser, SID_BASICIDE_OBJECT_BROWSER, was met with a series of build errors. It quickly became clear that this was more than a simple syntax issue. To solve it, I had to understand the history and design of the SFX2 dispatch system.

  2. I learned that for a command to work correctly, it needs to be registered in two places:

  • Globally (sfx2/sdi/sfx.sdi): This is where the command gets its universal .uno:ObjectBrowser name, making it available to the entire application for use in menus, toolbars, and keyboard shortcuts.

  • Locally (basctl/sdi/baside.sdi): This file maps the global command to a specific C++ method within the BASIC IDE's Shell, telling the framework what code to execute when the user is in the IDE's context.

Week 5: https://lists.freedesktop.org/archives/libreoffice/2025-June/093443.html

Gerrit patch 6: https://gerrit.libreoffice.org/c/core/+/186822/6

Here is the first time Object Browser UI was made available: https://bug-attachments.documentfoundation.org/attachment.cgi?id=201520

Week 6: The Stability & Architectural Rebirth !

From week 6 on-wards I started to bring too many things in single patch and also from here he UI problems started to not just emerge but also persisting and having serious side effects for all the future development.

Here initially while make this new UI stable in the IDE I started to treating the symptoms rather than looking for the disease which was my poorly integrated UI code. I placed the Object Browser as a global, persistent tool owned and managed directly by the top-level basctl::Shell. I then tried to inject this component into the transient ModulWindowLayout when the IDE editor was active.

This created a conflict of ownership. The persistent Shell and the transient ModulWindowLayout were both trying to manage the layout of sibling windows (the Object Browser and the legacy Object Catalog). This resulted in a race condition, corrupting the IDE's layout state and causing the reported crashes and visual glitches.

Here I went in the rabbit hole of all doing by myself in a hope of that I can get this done. But now when I am writing this a better approach would have been asking the mentors or community what could be possible reason for this UI bugs. But that is just not the case as the development keeps going I started to realize why cross-platform development is difficult :)

The solution I came up with at that was by simplifying the design and following the established pattern of the time-tested ObjectCatalog. Instead of being a special, shell-managed component, the Object Browser was redesigned to be a first-class citizen of the ModulWindowLayout.

While the basctl::Shell still owns the ObjectBrowser instance (as a VclPtr), the ModulWindowLayout is given full authority to manage its layout and lifecycle, just as it does for the ObjectCatalog.

void ModulWindowLayout::OnFirstSize(...)

AddToLeft(&rObjectCatalog, ...);

AddToLeft(GetShell()->GetObjectBrowser(), ...);

Yet this was still not correct and from my understanding this was the reason of all the UI problems which we faced. Which I learned after breaking down the patch.

Week 6: https://lists.freedesktop.org/archives/libreoffice/2025-July/093493.html

Gerrit Patch 10: https://gerrit.libreoffice.org/c/core/+/186822/10

Week 7: Bringing Data to UI

This week marks the major turning point where I understood how to exactly fetch the data I thought I could "discover" the UNO API tree on-demand by querying the API hierarchically. My plan was to call a function to get the children of "com", then the children of "com.sun", and so on, as the user expanded the tree. This approach simply did not work. The tree would not expand, and the process was unstable.

The UNO reflection API's XHierarchicalNameAccess::getByHierarchicalName() is designed for direct lookup of fully-qualified names (e.g., "com.sun.star.reflection.XIdlClass"), not for enumerating children of a partial namespace path like "com". The API has no getChildren() or listNames() method for discovery.

A better analogy: it's like a phone book where you can instantly look up 'Kriti Gupta' if you know the full name, but there's no way to ask 'show me everyone whose last name starts with K' without reading the entire book first.
So, naturally the idea was to hold this entire fetched API information to a place with a two-phase system

Phase 1: The One-Time Session Cache (Build the Map)

This happens once, in the background, when the data provider is initialized. It queries the TypeDescriptionManager singleton (via /singletons/com.sun.star.reflection.theTypeDescriptionManager) to enumerate all ~17,500 UNO type descriptions, then builds an in-memory hierarchical map m_hierarchyCache organized by namespace (e.g., com → sun → star → sheet).

Phase 2: Live UI Interaction (Use the Map)

With the map built, serving UI requests becomes a highly efficient, two-strategy process:

  1. For Tree Expansion (Discovery): GetChildNodes() performs an O(log N) map lookup in m_hierarchyCache to retrieve pre-built child lists for namespace nodes (e.g., children of "com.sun.star"). No runtime reflection calls are needed

  2. For Member Listing (Introspection): GetMembers() uses theCoreReflection->forName() to perform live introspection on a specific type (e.g., "com.sun.star.sheet.XSpreadsheet"), retrieving its methods, properties, and fields at the moment the user selects it.

The m_hierarchyCache implemented this week is a session cache: it lives only as long as the IDE is open and is rebuilt on each startup. This was the perfect solution to make the UI functional, and responsive. A final crash related to introspecting the generic template com.sun.star.beans.Ambiguous<T> was resolved by adding defensive if (xField.is()) checks, hardening the data provider.

Patch 14 for Week 7: https://gerrit.libreoffice.org/c/core/+/186822/14

UI populated with API Data: https://bug-attachments.documentfoundation.org/attachment.cgi?id=201757

Week 8: Solving the UI Freeze - The Two-Cache Architecture

With the data provider successfully fetching live data in Week 7, a new, critical problem emerged: the UI starts to freeze. When a user clicked to expand a node with thousands of children (like the top-level com namespace), the UI thread would block while attempting to render every single child node at once. This made the application unusable.

AND remind you this all happening on a single monolith patch which was improperly integrated by me and hence these all UI bugs are still the result of that.

Solving this required a new architectural layer. Our data provider's "Session Cache" was fast at providing the complete list of children, but the UI was too slow at consuming it. After discussing this with my mentors, I proposed a solution inspired by the progressive-loading patterns common in modern web UIs, like Instagram's bookmark folders. The core principle was to make the UI "dumber" means it shouldn't have to handle the entire dataset at once. We also had an idea of copying this session cache for the UI but, I went ahead with experimenting this bookmark/sticky note approach.

This led to the implementation of a Two-Cache System:

  1. The Session Cache (The Dictionary): This is the complete, in-memory map of all ~17,500 UNO entities that lives in the IdeDataProvider. It's built once in a background thread(a complex approach I chose) and acts as our single source of truth for the API hierarchy.

  2. The UI Bookmark Cache (The "Sticky Note"): This is a new, lightweight cache that lives in the ObjectBrowser UI layer itself. It's a simple std::map<OUString, size_t> m_aNextChunk that tracks the rendering progress for each expandable node, allowing the UI to render the children in manageable chunks (e.g., 50 at a time).

The OnNodeExpand handler is where the magic happens. It uses the bookmark cache to fetch and render only the next "chunk" of children from the data provider.

Gerrit Patch. 18: https://gerrit.libreoffice.org/c/core/+/186822/18

Screen Shot Week 8: https://bug-attachments.documentfoundation.org/attachment.cgi?id=201912

Weeks 9 & 10: Crashes & Race Conditions

After being able to populate the UI in the previous weeks, the Object Browser was functional but deeply unstable. The application was plagued by critical crashes during shutdown and severe performance lag during startup. Weeks 9 and 10 were a transformative period dedicated to slaying these stability dragons. This diagnostic journey led to a complete re-architecture of the component's lifecycle management, transforming it from a fragile prototype into a rock-solid foundation.

Problem 1: The Shutdown Crashes

The most pressing issue was a series of fatal crashes when closing the IDE, especially on macOS. Systematic testing revealed two distinct failure modes:

  1. TaskPanelList Registration Failure: A fatal error indicating a window was still registered in the UI's side panel manager after it should have been destroyed.

  2. Post-Disposal Mouse Event Crash: A use-after-free crash where the operating system was still delivering mouse events to the SalFrameView of the Object Browser after its C++ object had been deleted. It was the parent UI of Object Browser BASIC Macros which was causing it again because I did not integrated the Object Browser well in the initial period and kept dragging everything in the same patch.

So the steps to fix the TaskPanelList bug was to implement a strict, non-negotiable shutdown protocol which was guided by Prof. Lima and his testing on his own machine.

In void ObjectBrowser::dispose()

// STEP 1: Announce Disposal to All Threads Immediately.

// STEP 2: Unregister from External Systems.

if (GetParent() && GetParent()->GetSystemWindow())

{

if (auto* pTaskPaneList = GetParent()->GetSystemWindow()->GetTaskPaneList())

pTaskPaneList->RemoveWindow(this);

}

// STEP 3: Disconnect All Event Handlers.

Problem 2: The Initialization Hydra and Performance Lag

With shutdown stabilized, the focus shifted to a severe performance problem: the IDE would hang for over 6 seconds on startup, and logs revealed multiple UnoHierarchyInitThread instances being created.

The root cause was a race condition. Multiple UI events were triggering the AsyncInitialize() method on the IdeDataProvider before the first expensive initialization process had completed. My initial attempt to fix this with a simple boolean flag was insufficient.

The only cure was a complete redesign of the initialization logic, creating a synchronized, thread-safe state machine across both the ObjectBrowser and IdeDataProvider.

The New Architecture: A Coordinated State Machine

This system uses modern C++ threading primitives to guarantee that the expensive data-loading process runs exactly once.

  1. In ObjectBrowser::Initialize(): A Double-Checked Locking Pattern was implemented. It uses a fast, lock-free std::atomic read first. Only if initialization has not started does it acquire a std::mutex for a second, definitive check before proceeding. This is highly efficient and prevents race conditions.

  2. In IdeDataProvider::AsyncInitialize(): An atomic compare_exchange_strong operation is used. This is a powerful, indivisible hardware-level instruction that says: "IF the 'in progress' flag is false, SET it to true and return success." Only the very first thread to call this method wins the race; all subsequent calls fail the check and exit immediately.

This multi-layered approach was success, resulting in an 80% reduction in initialization time (from over 6 seconds down to ~1.2 seconds) and eliminating the startup hang. Yet this is a solution to those symptoms which are entirely caused by me.

Patch 27 (Week 9): TaskPanelList Disposition Fix - https://gerrit.libreoffice.org/c/core/+/186822/27

Patch 28 (Week 10): Thread-Safe Initialization System - https://gerrit.libreoffice.org/c/core/+/186822/28

Week 11: Ghost Parent & Fixing Crash

After the major stability and performance wins of the previous weeks, my focus in Week 11 turned to what I believed was a complex, platform-specific bug. As I documented in my report, the IDE was suffering from a crash on macOS related to mouse events, specifically in -[SalFrameView mouseDown:].

My investigation went through four distinct phases, a deep and challenging debugging process that, ironically, led me right back to the architectural flaws I had tried to solve in Week 6.

Phase 1 & 2: The Red Herring - A macOS-Specific Bug?

My initial theory was that this was a use-after-free crash specific to the macOS Cocoa event system occurring in -[SalFrameView mouseDown:]. The crash logs pointed to mouse events being delivered to a disposed window object. I spent a significant amount of time exploring NSTimer cleanup and the AquaSalFrame tracking system, researching VCL's lifecycle and adding safeguards. However, none of my initial fixes worked. This was a frustrating but important clue: the problem was deeper than a simple platform bug and it was which I realized after breaking down the patch.

Phase 3 & 4: The Real Culprit - A Flawed UI Lifecycle?

The breakthrough came when I discovered the crash only happened under a specific condition: launching the IDE from "Tools > Macros > Edit" without a document open. In this scenario, the parent "BASIC Macros" dialog would remain on-screen as a non-functional "ghost," and clicking it would cause the crash.

This "Ghost Parent" was the real symptom. I deduced this wasn't a macOS issue at all, it was a fundamental flaw in the application's UI lifecycle. The problem I was chasing was a direct consequence of the fragile UI integration I had built back in Week 6. The synchronous way the IDE was being launched was blocking the UI thread, preventing the parent "BASIC Macros" dialog from closing properly. Again entirely built on the premise of poor UI integration and understanding.

I thought this synchronous launch was creating a "zombie" window that was still technically alive but in an inconsistent state, and my new Object Browser, being part of this fragile hierarchy, was exposing and exacerbating this latent bug. The crash was a symptom of this deeper architectural problem.

The Fix(not exactly): Asynchronous IDE Launch

My theory was the solution had nothing to do with macOS-specific code. It was to re-architect the way the IDE is launched from the "BASIC Macros" dialog, making it asynchronous. This change, which I was investigating at the end of this period, would allow the parent dialog to close itself cleanly before the IDE finished launching, thus preventing the "ghost window" from ever being created.

A Flawed Shutdown and the TaskPanelList Crash

Systematic testing revealed that the IDE would reliably crash on shutdown, even on systems other than macOS. The log provided the crucial clue:

Window ( N6basctl13ObjectBrowserE(Object Browser)) still in TaskPanelList!

Fatal exception: Signal 6

The diagnosis was clear: my dispose() method was an uncontrolled demolition. It was destroying all the internal widgets before unregistering the Object Browser from the IDE's TaskPanelList, a high-level manager for side panels. This left a dangling pointer in the TaskPanelList, which the framework would then try to access during shutdown, causing a fatal crash.

Unregister from all external systems first, then disconnect internal event handlers, and only then destroy the internal state and widgets. This disciplined, "outside-in" approach completely resolved the shutdown crashes.

Gerrit Patch 29: https://gerrit.libreoffice.org/c/core/+/186822/29

Gerrit Patch 30: https://gerrit.libreoffice.org/c/core/+/186822/30

Patch 30 working Video: https://www.youtube.com/watch?v=gTwWkYQKLxk

Week 12-14: Changing Approach

The final weeks of this big monolith patch phase were not about adding new features, but about confronting a critical stability bug that had plagued the project since the very beginning: the "Ghost Parent" crash. This issue, a direct result of the flawed UI integration I had implemented back in Week 6, was the single biggest blocker to progress in my understanding and the other UI integration which I made on a really complex thread based data-provider. The investigation was a multi-week deep dive that taught me profound lessons about VCL's lifecycle and the necessity of a methodical, small steps which I should have been taking since the beginning.

The Original Sin: The Flawed UI Integration of Week 6

The root of the problem was architectural. My initial integration of the Object Browser treated it as a special, shell-managed component, creating a conflict of ownership with the ModulWindowLayout. This flawed design was the source of a cascade of stability issues, the most severe of which was the "Ghost Parent" crash.

The Symptom (A Long-Standing Bug):

When launching the IDE from "Tools > Macros > Edit" without a document open, the parent "BASIC Macros" dialog would remain on screen as a non-functional "ghost." Clicking this ghost window would reliably crash the entire application. For weeks, I had mistakenly chased this as a macOS-specific bug, going down a rabbit hole of NSTimer and SalFrameView internals, when in fact it was a platform-agnostic deadlock I had created.

While the stability investigations dominated this period, the core feature work on the monolith had been completed. The search functionality, in particular, was fully implemented in the backend, ready to be extracted.

It was at this point, faced with a massive, buggy patch and a complex fix, that a crucial strategic discussion with my mentors, particularly Jonathan Clark, took place. We acknowledged that the monolith had served its purpose as a prototype but was now an obstacle to progress. Its size and instability meant we were spending all our time fighting fires rather than making forward progress.

The path forward was no longer to "fix the monolith." The new, mentor-guided strategy was to abandon the single-patch approach and begin the disciplined process of breaking it down into a series of clean, logical, and reviewable patches. This also led to the necessary discussion of extending the project timeline to ensure we could do this properly. The focus shifted from adding features to methodical, stable engineering.

I think without them the project where it is now wouldn't be possible and then we started breaking down the patch and yet I kept making mistakes but lets see how those patch breakdown happened.

Week 12-13 Mail: http://lists.freedesktop.org/archives/libreoffice/2025-August/093738.html

Week 14 Mail: https://lists.freedesktop.org/archives/libreoffice/2025-September/093784.html

Images:

BASIC IDE launch without STATIC ASYNC IDE handler - https://bug-attachments.documentfoundation.org/attachment.cgi?id=202573

BASIC IDE launch with STATIC ASYNC IDE handler - https://bug-attachments.documentfoundation.org/attachment.cgi?id=202574

post patch 32 grouped search

https://bug-attachments.documentfoundation.org/attachment.cgi?id=202575

https://bug-attachments.documentfoundation.org/attachment.cgi?id=202576

Monolith Patch 37 - https://gerrit.libreoffice.org/c/core/+/186822

Breaking Down of the patches.

Here is where the real learning happened for me and I started to see how breaking down chronologically the patches makes everything not just easier but enjoyable to work with. I spent more time here not because I have to met the new deadline but I really started to enjoy it when I can now see the immediate next thing to fix which means instead of a scattered fuzzy goal I have a visible binary goal of what to do next.

Patch 1: Core Data Structures

This foundational patch establishes the skeleton infrastructure for the BASIC IDE Object Browser feature. This patch does not introduce any user-visible features. Its sole purpose is to define the core data structures and C++ class skeletons for the entire Object Browser project. It is the bedrock upon which all subsequent features are built.

Key Files Introduced:

  • include/basctl/idecodecompletiontypes.hxx: The public header defining the core data structures.

  • basctl/source/basicide/idecodecompletiontypes.cxx: The implementation file for these structures.

  • basctl/source/inc/objectbrowser.hxx & idedataprovider.hxx: Header files for the main classes.

  • basctl/source/basicide/objectbrowser.cxx & idedataprovider.cxx: Empty implementation files for these classes.

  • basctl/Library_basctl.mk: Build system file to include all the new source files.

Symbol Type System (include/basctl/idecodecompletiontypes.hxx)

  • Defines IdeSymbolKind enum covering all symbol types: BASIC constructs (functions, variables, UDTs), UNO types (services, interfaces), and UI nodes.

  • The IdeSymbolInfo struct stores comprehensive metadata about symbols including name, type, parameters, and hierarchical relationships.

Performance Timer (basctl/source/basicide/idetimer.cxx)

Timer using osl_getSystemTime() - captures start time on construction, logs elapsed time on destruction via SAL_INFO. Will be used to profile initialization in later patches.

Gerrit Patch Link: https://gerrit.libreoffice.org/c/core/+/189934

Patch 2:Integrating the Blank Shell UI

With the core data structures in place from the first patch, our next goal was to build and integrate the visible user interface. This patch represents the "View" in our MVC architecture(which I like). It takes the abstract classes from the previous step and connects them to a real, visible window within the BASIC IDE.

This was a significant undertaking that touched multiple layers of the application, from the UI definition and build system to the core IDE lifecycle management. The primary achievement of this patch is a visible, dockable, and correctly managed (though still empty) Object Browser window.

Key Files Introduced or Modified:

  • basctl/uiconfig/basicide/ui/objectbrowser.ui: The new GTKBuilder file that defines the layout and widgets of the Object Browser.

  • basctl/source/basicide/objectbrowser.cxx/.hxx: Significantly expanded to load the UI file, get pointers to the widgets, and handle its lifecycle.

  • basctl/sdi/sfx.sdi, basctl/sdi/baside.sdi, menubar.xml: Files that register the .uno:ObjectBrowser command and add it to the "View" menu.

  • basctl/source/basicide/baside2.cxx, baside3.cxx: The core IDE layout managers, modified to own and manage the new Object Browser window.

Technical Deep Dive

Defining the User Interface basctl/uiconfig/basicide/ui/objectbrowser.ui

The visual structure of the Object Browser is defined in a standard .ui file. This patch introduces the complete layout, including the search bar, scope selector, back/forward buttons, the main splitter panes for the object and member trees, and the detail pane at the bottom.

Loading the UI and Connecting Widgets https://gerrit.libreoffice.org/c/core/+/191206/22/basctl/source/basicide/objectbrowser.cxx

The ObjectBrowser C++ class is now responsible for loading this .ui file and "welding" its definitions to C++ widget objects. The Initialize method is expanded to get pointers to all the key widgets so they can be controlled from code.

Lifecycle Management and Integration

This is the most critical part of the patch. To ensure stability, I followed the architectural lesson from my monolith experiments: the Object Browser's lifecycle must be managed by the same authority as the existing ObjectCatalog. This patch modifies the ModulWindowLayout and DialogWindowLayout classes to take ownership of the ObjectBrowser's layout and visibility.

This patch successfully builds upon the foundation of the first one. It moves the project from an abstract set of data structures to a tangible, visible, and properly integrated UI component. By learning from the mistakes of the monolith and integrating the Object Browser according to the VCL framework's established patterns, this patch achieves a stable UI shell. Although it's still an empty shell with no data, it is a correctly behaved one. It appears in the menu, it can be shown and hidden, it docks correctly, and it doesn't crash the IDE. This stable "View" is now ready to be connected to the "Model" (`IdeDataProvider`).

Gerrit Patch 2: https://gerrit.libreoffice.org/c/core/+/191206

Background thread + caching old approach - https://www.youtube.com/watch?v=XE5QLT2HKIw (THIS APPROACH IS REVERTED)

Patch 3:The Synchronous Solution

With the UI shell in place, the next logical step was to populate it with data. This patch implements the core data-fetching logic in the IdeDataProvider, connecting the "Model" to the "View." However, the path to the final solution was a journey of iteration and discovery, reflecting the project's shift from complex, premature optimization to simple, data-driven design.

The Initial Approach: A Monolith Throwback

My first instinct, based on the work from the monolith, was to reuse the background threading approach. I believed that the UNO API scan, which involves iterating through ~17,500 types, was too slow to run on the main UI thread. My initial implementation in this patch series involved a background thread, a caching system, and all the complexity that comes with asynchronous programming. As a refinement, I even prototyped a cooperative multitasking approach, using timers to break the scan into small chunks to keep the UI responsive.

The Pivot: Data-Driven Simplicity

This is where my mentor, Jonathan Clark, guided me toward a crucial engineering principle: don't optimize prematurely. He prompted me to actually measure the performance of a simple, synchronous scan. I used XCode Instruments and also I tried the Google Benchmark too to benchmark the operation.

The results were a complete surprise and a game-changing moment for the project.

The Performance Data:

  • Debug Build: Operation 'IdeDataProvider::performFullUnoScan' took 1.87 seconds. (Slow, but expected for a debug build)

  • Release Build: Operation 'IdeDataProvider::performFullUnoScan' took 0.157 seconds.

  • Release Build (with string_view optimization): Operation 'IdeDataProvider::performFullUnoScan' took 0.122 seconds.

As Jonathan noted, a 0.15-second delay is negligible for a one-time operation. The data proved that the complexity of a background thread was completely unnecessary. Based on this hard evidence, we made the decision to discard the complex asynchronous code and adopt a simple, synchronous Initialize() method. This dramatically simplified the codebase, removed potential race conditions, and made the entire system easier to understand and maintain.

My Google Benchmark result for Synchronous way of fetching API details and Building the Session Cache -

⚡devanshvarshney ❯❯ ./workdir/LinkTarget/Executable/basctl_benchmark_addnode Unable to determine clock rate from sysctl: hw.cpufrequency: No such file or directory This does not affect benchmark measurements, only the metadata output. ***WARNING*** Failed to set thread affinity. Estimated CPU frequency may be incorrect. 2025-10-02T21:46:22+05:30 Running ./workdir/LinkTarget/Executable/basctl_benchmark_addnode Run on (10 X 24 MHz CPU s) CPU Caches: L1 Data 64 KiB L1 Instruction 128 KiB L2 Unified 4096 KiB (x10) Load Average: 2.63, 2.62, 2.58 ---------------------------------------------------------------------------------------------------------------------------- Benchmark Time CPU Iterations UserCounters... ---------------------------------------------------------------------------------------------------------------------------- BM_AddNode_AllUnoTypes/min_time:10.000/repeats:3/real_time_mean 163 ms 162 ms 3 TotalTypes=17.581k items_per_second=107.746k/s BM_AddNode_AllUnoTypes/min_time:10.000/repeats:3/real_time_median 162 ms 162 ms 3 TotalTypes=17.581k items_per_second=108.397k/s BM_AddNode_AllUnoTypes/min_time:10.000/repeats:3/real_time_stddev 1.78 ms 0.330 ms 3 TotalTypes=0 items_per_second=1.16613k/s BM_AddNode_AllUnoTypes/min_time:10.000/repeats:3/real_time_cv 1.09 % 0.20 % 3 TotalTypes=0.00% items_per_second=1.08%

Technical Deep Dive

UNO Type Hierarchy Builder (UnoApiHierarchy struct in idedataprovider.hxx)

Builds an in-memory tree of all UNO types using m_hierarchyCache map:

struct UnoApiHierarchy

{

std::map<OUString, SymbolInfoList> m_hierarchyCache;

void addNode(std::u16string_view sQualifiedName, TypeClass eTypeClass);

};

The addNode() method parses dotted names like "com.sun.star.frame.XFrame" and creates namespace nodes for each segment, with the final segment getting the actual type kind (interface, struct, etc.). It uses typeClassToSymbolKind() to map UNO TypeClass enum to IdeSymbolKind.

Full UNO Scan (performFullUnoScan() in idedataprovider.cxx)

Enumerates all UNO types using the reflection API:

Reference<XTypeDescriptionEnumerationAccess> xEnumAccess(xTypeManager, UNO_QUERY_THROW);

Reference<XEnumeration> xEnum = xEnumAccess->createTypeDescriptionEnumeration( u""_ustr, {}, TypeDescriptionSearchDepth_INFINITE);

while (xEnum->hasMoreElements())

{ m_pUnoHierarchy->addNode(xTypeDesc->getName(), xTypeDesc->getTypeClass()); }

BASIC Library Preloading (Initialize() method)

Loads all application and document libraries synchronously to ensure symbols are available:

ScriptDocument aAppDoc = ScriptDocument::getApplicationScriptDocument();

Reference<XLibraryContainer> xLibContainer = aAppDoc.getLibraryContainer(E_SCRIPTS);

for (const OUString& rLibName : xLibContainer->getElementNames())

{ if (!xLibContainer->isLibraryLoaded(rLibName)) xLibContainer->loadLibrary(rLibName); }

Iterates through all open documents and preloads their libraries too.

Root Node Creation (CreateRootIdentifier() helper)

Generates unique IDs for top-level browser nodes:

OUString CreateRootIdentifier(IdeSymbolKind eKind, std::u16string_view sOptionalPayload)

{

switch (eKind)

{

case IdeSymbolKind::ROOT_UNO_APIS: return "root:uno_apis";

case IdeSymbolKind::ROOT_APPLICATION_LIBS: return "root:app_macros"; // ...

} }

UI Integration (ObjectBrowser::Show() changes)

Replaces async callback with synchronous call wrapped in weld::WaitObject (shows busy cursor):

if (!m_pDataProvider->IsInitialized())

{

ShowLoadingState();

weld::WaitObject aWait(GetFrameWeld()); // Busy cursor

m_pDataProvider->Initialize(); // Synchronous!

RefreshUI();

}

Gerrit Patch: https://gerrit.libreoffice.org/c/core/+/191405

Patch 4: Scope Selector & Dynamic Refresh

Building on the functional data provider from the previous patch, my next objective was to make the Object Browser interactive and context-aware. This patch brings the "Scope" dropdown menu to life, allowing users to switch their view between "All Libraries" (the default) and "Current Document." This is a crucial feature for helping users focus on the macros and objects relevant to their immediate task.

More importantly, this patch introduces a dynamic refresh mechanism. The Object Browser now listens for application-wide events and automatically updates its view when the user switches between open documents, but only when the "Current Document" scope is active.

Key Files Modified:

basctl/source/basicide/objectbrowser.cxx/.hxx: Major changes to handle UI events, listen for application-wide document activation, and manage the scope state.

basctl/source/basicide/idedataprovider.cxx/.hxx: Updated to filter the top-level nodes based on the currently selected scope and active document.

Scope Filtering System (IdeBrowserScope enum in idedataprovider.hxx)

Defines two viewing modes:

enum class IdeBrowserScope

{

ALL_LIBRARIES, // Show all documents

CURRENT_DOCUMENT // Show only active document

};

Technical Deep Dive

Document Node Management (AddDocumentNodesWithModules() and RefreshDocumentNodes())

Scans all open documents and adds them as top-level nodes only if they contain BASIC modules:

1. Activating the Scope Dropdown

The first step was to connect the OnScopeChanged handler to the UI. When the user changes the selection in the "Scope" dropdown, this handler is now called. It updates the data provider with the new scope and triggers a full refresh of the UI.

2. Implementing Scope-Based Filtering in the Data Provider

The IdeDataProvider is now aware of the current scope. It dynamically filters the master list of all nodes (m_aAllTopLevelNodes) based on the selected scope.

3. Listening for Document Changes

To make the "Current Document" scope truly dynamic, the ObjectBrowser now inherits from SfxListener and registers itself to listen for application-wide events. The Notify method filters for the SfxEventHintId::ActivateDoc event, which is fired whenever the user switches to a different document window.

This patch transforms the Object Browser from a static display into a dynamic and context-aware tool. By implementing the scope selector and listening for document activation events, the browser can now intelligently filter its display to match the user's focus. The clean separation of concerns is key: the ObjectBrowser (View/Controller) handles UI events and application notifications, while the IdeDataProvider (Model) encapsulates the filtering logic. This lays the groundwork for a more intuitive and powerful user experience, where the tool adapts to what the developer is actively working on.

Gerrit Patch: https://gerrit.libreoffice.org/c/core/+/191886

Patch 5: UI Interactivity & Member View

With a stable data provider and a functional scope selector in place, this patch delivers the most significant leap in user-facing functionality yet. It brings the Object Browser's core UI to life by implementing the two primary user interactions: expanding nodes in the left-hand tree and displaying the members of a selected item in the right-hand pane.

This is the moment the Object Browser transitions from a static list into a dynamic, two-pane exploration tool.

To connect the user's actions in the left navigation pane to the data provider and display the results appropriately, making the interface interactive and data-aware. This involves implementing:

  1. On-Demand Node Expansion: Loading and displaying the children of a node only when the user clicks its expander arrow.

  2. Member View Population: When a user selects an item (like a module or UNO interface), its members (subs, functions, methods, properties) are fetched and displayed in the right-hand pane.

Key Files Modified:

  • basctl/source/basicide/objectbrowser.cxx/.hxx: This is where the bulk of the logic lives. The OnNodeExpand and OnLeftTreeSelect event handlers are now fully implemented.

  • basctl/source/basicide/idedataprovider.cxx: Expanded to provide children of BASIC libraries and members of both UNO types and BASIC modules.

  • basctl/uiconfig/basicide/ui/objectbrowser.ui: Updated to support icons in the tree views.

Technical Deep Dive

1. On-Demand Node Expansion (OnNodeExpand)

The connect_expanding signal of the LeftTreeView is now wired to a real implementation. When a user expands a node, this handler is called. It gets the corresponding IdeSymbolInfo for the expanded node, asks the IdeDataProvider for its children, and then adds those children to the tree view.

2. Member View Population (OnLeftTreeSelect and PopulateMembersPane)

The connect_selection_changed signal of the LeftTreeView is now also implemented. When a user selects a node:

  1. The OnLeftTreeSelect handler is called.

  2. It determines if the selected symbol is one that should have members (e.g., a MODULE or UNO_INTERFACE).

  3. If so, it calls the new PopulateMembersPane helper method.

  4. PopulateMembersPane asks the IdeDataProvider for the members, groups them by kind (Properties, Methods, etc.), and populates the RightMembersView.

This is the patch where the Object Browser becomes truly useful.

  • A Fully Interactive Tree: The left-hand pane is no longer a static list. Users can now expand nodes and explore the entire UNO and BASIC library hierarchies on demand.

  • The Core "Browser" Feature: The two-pane browser model is now fully functional. Selecting a container on the left correctly displays its contents on the right.

  • Categorized Member Display: Members in the right-hand pane are logically grouped (Properties, Methods, etc.), making the view clean and easy to navigate.

Gerrit Patch: https://gerrit.libreoffice.org/c/core/+/191923/

Patch 6: Right-Pane & Documentation Link

With the core data structures in place from the first patch, our next goal was to build and integrate the visible user interface. This patch represents the "View" in our MVC architecture(which I like). It takes the abstract classes from the previous step and connects them to a real, visible window within the BASIC IDE.

With the left-hand tree now fully interactive, this patch focuses on enriching the user experience in the right-hand "Members" pane. It introduces two major features that are essential for a modern development tool: on-demand expansion of nested types and a context-aware double-click action that connects the IDE to external API documentation and internal source code.

This patch transforms the right pane from a static list into a powerful, interactive tool for deep API exploration and code navigation.

To make the right-hand members pane fully interactive and useful as a developer tool. This includes:

  1. Nested Type Expansion: Allowing users to expand complex UNO types (structs, interfaces) directly within the members list to see their nested members.

  2. Double-Click Actions: Implementing a "double-click" or "row activated" event that performs a context-sensitive action, such as opening API documentation or navigating to source code.

Technical Deep Dive

1. On-Demand Expansion of Nested Members

The data provider is now smarter. When fetching the members of a UNO type, it recursively inspects the type of each field. If a field is itself a complex type (like a struct), it pre-fetches its members and stores them in the mapMembers of the parent IdeSymbolInfo.

The UI's PopulateMembersPane method was then updated to check for these nested members and set the bChildrenOnDemand flag to true when adding the entry to the RightMembersView. A new event handler, OnRightNodeExpand, was added to render these pre-fetched nested members when the user expands the node.

2. Context-Aware Double-Click Actions

A new event handler, OnRightTreeDoubleClick, was connected to the row_activated signal of the RightMembersView. This handler contains the core logic for determining the correct action based on the type of symbol the user double-clicked.

  • For BASIC Symbols (SUB, FUNCTION): It navigates directly to the source code.

  • For UNO Symbols (UNO_INTERFACE, etc.): It opens the relevant online API documentation in the web browser.

3. Navigating to Source Code (NavigateToMacroSource)

A new helper method was created to handle navigation for BASIC code. It constructs an SbxItem, which is a special data structure that holds information about a BASIC symbol (document, library, module, and method name). It then uses the global SFX Dispatcher to execute the SID_BASICIDE_SHOWSBX command, which tells the IDE to open the correct module and jump to the specified line.

In void ObjectBrowser::NavigateToMacroSource(const IdeSymbolInfo& rSymbol)

SbxItem aSbxItem(SID_BASICIDE_ARG_SBX, aDoc, rSymbol.sOriginLibrary, rSymbol.sOriginModule, rSymbol.sName, basctl::SBX_TYPE_METHOD);

4. Opening External Documentation (OpenDoxygenDocumentation)
Another new helper was created to handle UNO types.

  • BuildDoxygenUrl: This function intelligently constructs the correct URL for the official API documentation by converting the symbol's qualified name (e.g., com.sun.star.sheet.XSpreadsheet) into the format used by the Doxygen website (e.g., interfacecom_1_1sun_1_1star_1_1sheet_1_1XSpreadsheet.html).

  • OpenDoxygenDocumentation: This function uses the XSystemShellExecute service, a platform-agnostic way to open a URL in the user's default web browser.

Member Caching for Performance

To avoid repeatedly fetching members for the same object, I introduced a simple caching layer in the IdeDataProvider. The first time GetMembers is called for a symbol, it fetches the data and stores it in a map (m_aMembersCache) keyed by the symbol's unique identifier. Subsequent calls return the cached data instantly. If a user clicks back and forth between two symbols repeatedly, we don't want to re-introspect the same object over and over. This cache stores the results of the GetMembers call.

And the Session Cache is - Its sole purpose is to solve the Discovery problem for the UNO API in Patch 3.


std::unique_ptr<UnoApiHierarchy> m_pUnoHierarchy; (which internally contains std::map<OUString, SymbolInfoList> m_hierarchyCache;)

Gerrit Patch: https://gerrit.libreoffice.org/c/core/+/192050

Patch 7: Details Pane & Status Bar

With the core interactivity in place, this patch focuses on making the Object Browser truly informative. It activates the two remaining UI elements: the main details pane at the bottom and the status bar. This work transforms the browser from a simple navigator into a proper inspection tool, providing rich, contextual information about any selected symbol.

When a user selects an item, the details pane now displays a formatted signature, showing parameters, return types, and location information. The status bar provides at-a-glance context, such as member counts, and, upon initial load, proudly displays the total time taken for the data provider to initialize, closing the loop on our performance investigation.

Key Files Modified:

  • basctl/source/basicide/objectbrowser.cxx/.hxx: Contains the new formatting logic and the updated event handlers to refresh the information panes.

  • basctl/source/basicide/idedataprovider.cxx: Enhanced to extract detailed parameter information from BASIC macros.

  • basctl/inc/strings.hrc: A large number of new string resources were added to support the rich formatting in the details pane.

Technical Deep Dive

1. The Details Pane and Rich Signature Formatting


The centerpiece of this patch is the FormatSymbolSignature function. This is a sophisticated helper that takes an IdeSymbolInfo object and builds a detailed, human-readable description. It handles different symbol kinds, formats method parameters with ByRef/Optional keywords, and includes location information like the library and document.

2. Extracting Detailed BASIC Parameter Info

To provide full signatures for BASIC macros, I had to enhance the IdeDataProvider. The ImplGetMembersOfBasicModule function now introspects the compiled SbMethod object to extract not just parameter names, but also their types and whether they are ByRef or Optional.

3. The Contextual Status Bar

The status bar is now wired up to provide helpful, context-sensitive information. The UpdateStatusBar method is called on every selection change and displays different information based on what is selected in the left and right panes, such as the total member count for a selected container. Crucially, it also displays the final load time after the initial synchronous Initialize is complete.

This patch completes the core user experience of the Object Browser. By providing rich, formatted information in the details pane and contextual feedback in the status bar, the tool is now not just a navigator but a genuine source of information for the developer. The ability to see full method signatures for both UNO and BASIC objects is a major step forward. This patch demonstrates a focus on user-centric design, transforming raw data into a polished and helpful presentation. With this, the foundational "browsing" aspect of the Object Browser is complete and robust.

Gerrit Patch: https://gerrit.libreoffice.org/c/core/+/192079/

Patch 8: Activating the Search Engine

With the core browsing and display features now stable and functional, this patch resurrects a key feature from the original monolith: the search functionality. This transforms the Object Browser from a purely navigational tool into a powerful discovery engine, allowing users to instantly find any symbol across the entire UNO API and loaded BASIC libraries.

This implementation is a thoughtful evolution of the monolith's design. It introduces an asynchronous, idle-time indexing process to avoid impacting startup performance, a debounced UI for a smooth user experience, and a ranked search algorithm for more relevant results.

Key Files Modified:

  • basctl/source/basicide/objectbrowsersearch.cxx/.hxx: This new class encapsulates all the logic for search, including UI event handling, debouncing, index building, and displaying results.

  • basctl/source/basicide/idedataprovider.cxx: Enhanced to support the recursive creation of a "flat index" of all symbols, which is the foundation for the search index.

  • basctl/source/basicide/objectbrowser.cxx: Updated to integrate the new ObjectBrowserSearch class and provide helper methods for displaying search results.

Technical Deep Dive

1. Asynchronous, Idle-Time Indexing

The most significant architectural choice in this patch is how the search index is built. Instead of blocking the UI during the initial data load, the index construction is deferred and performed during application idle time.

ObjectBrowser::Show() now calls a new method, m_pSearchHandler->StartAsyncIndexBuild().

This method starts an Idle timer with the lowest priority. The timer will only fire when the application is not busy with other tasks.

When the IdleIndexBuildHandler is triggered, it performs the expensive work of building the full-text search index.

2. The Search Index and Ranking Algorithm

The BuildSearchIndex method creates a flat list of every single browsable symbol (including nested members of UNO types and BASIC modules) and then builds a std::map (m_aSearchIndex) where keys are lowercase names.

The Search method then queries this index with a three-tiered ranking algorithm:

  • Score 100 (Exact Match): First, it looks for an exact match of the search term in the map keys.

  • Score 50 (Starts-With Match): Next, it iterates through the index to find all keys that start with the search term.

  • Score 10 (Substring Match): Finally, it performs a broad substring search.

The results are then sorted by score, ensuring the most relevant matches appear at the top of the list.

3. Debounced UI and Results Display


The UI interaction follows the debounced pattern from the monolith. OnFilterChanged starts a 350ms timer. When the timer fires, PerformSearch is called. The results are then passed to DisplaySearchResults, which:

  • Clears the previous view.

  • Calls BuildSearchResultHierarchy to group the flat list of results into a browsable tree (e.g., under "UNO APIs", "Application Macros").

  • Populates the LeftTreeView with this new temporary hierarchy.

  • Calls AutoExpandSinglePath to automatically expand nodes that have only one child, quickly drilling down to the relevant result for the user.

Recursion Protection in ImplGetMembersOfUnoType() -

constexpr sal_uInt16 nMaxRecursionDepth(8);

This patch delivers a complete, performant, and user-friendly search experience.

  • Responsive UI: The asynchronous indexing and debounced input ensure the IDE never freezes, either at startup or while typing.

  • Relevant Results: The ranked search algorithm provides a superior user experience by showing the most likely matches first.

  • Hierarchical Display: Search results are not just a flat list but are presented in a familiar, browsable tree structure that provides context.

  • Comprehensive Indexing: The search index now includes not only top-level items but also all members of UNO types and BASIC modules, making it a truly global search.

Gerrit Patch: https://gerrit.libreoffice.org/c/core/+/192079

Working of Object Browser: https://www.youtube.com/watch?v=-TqSmjFQ5hI

My Experience with GSoC 2025

What is my favourite part of participating in GSoC?

Learning not just how to think, but what to think. This year I just enjoyed working and kept sharing what I was solving with my friends.

What do I consider the most challenging part of participating in GSoC?

Paying attention to details. I have a hard time keeping my attention and working in GSoC has highlighted this for me more. I kept missing details right in front of me, like I just noticed 2 months back that in previous year proposal I wrote the year 2023 at the very front page. This missing out of details kept showing till the last patch 8 but I cannot thanks Jonathan to keep up with all these tiny details and showing me how to really look at the details.

A Deeper Lesson from a Simple Helper: The IdeTimer Story

During the development of the Object Browser, I created a small IdeTimer helper class to benchmark performance. A detail in its implementation became the source of a valuable, practical lesson in software engineering that occurred during the code review process.

The method in question was getElapsedTimeMs(). In my initial implementation, I also included this if block in the destructor to handle cases where the nanosecond calculation resulted in a negative value, which felt unintuitive to me.

For example, if an operation started at 10.9s and ended at 11.1s.

My initial implementation instinctively handled this by adding an if block to perform the borrow explicitly:

sal_Int64 IdeTimer::getElapsedTimeMs() const

{

TimeValue aEnd; osl_getSystemTime(&aEnd);

sal_Int32 nSeconds = aEnd.Seconds - m_aStart.Seconds;

sal_Int32 nNanos = aEnd.Nanosec - m_aStart.Nanosec;

// This is the "if block" in question

if (nNanos < 0) { nSeconds--; nNanos += 1000000000; }

return (static_cast<sal_Int64>(nSeconds) * 1000) + (nNanos / 1000000);

}

It took me a while to get it even if the time seems negative the Math is working out perfectly. This experience was a practical lesson in the principle of simplicity and avoiding over-engineering. My initial discomfort with a negative intermediate value led me to write code that, while functional, was ultimately unnecessary. The key takeaway was to trust the well-defined mathematical properties of the data types I am using. The code review process worked exactly as it should: it challenged an assumption, led to a deeper understanding, and resulted in simpler, cleaner code.

How has GSoC helped improve my programming skills?

Everyone keeps talking about what and how to write good code, but I learned, or if I say realize where to write the code.

There is this dialogue of Kevin Spacey from House of Cards, “Power is a lot like real estate. It's all about location, location, location. The closer you are to the source, the higher your property value.

I perceive it as code is pretty similar to power where you are putting your code will decide the entire structure and complexity of the code. But more than that compared to last year this year I am feeling comfortable with the codebase and after woorking on this work of BASIC IDE has given me really deep dive in the codebase. Implementing complexe or practically unwanted solutions and frankly it does costed the time where we could have acheived the complete work of this project but those mistakes gave me really good understanding of how NOT to really approach to solve a problem.

What advice would I give to contributors participating in GSoC in the future?

Define your goal of the day what you are going to do. Like for example I said that today I will send a mail or say I will complete the given document and it kept getting derailed because I wasn't defining what needs to be done in how much time.
If a bug or implementation is taking time I went on spending my entire day on it and not being able to catch-up what I said I will do.

Don't let that happen, I will start to define what I am going to do and place with a sticky-note in front of my screen which I asked Tomaž my last year mentor how he organizes his day? So, I am goign to incorporate this onward.

How do I rate myself for participating in GSoC?

Compared to last year this year after more than 4 months of wokring and constantaly seeing the code and yeah implementing unnecessary complexe solutions I now while writing this am comfortable and now can work Independantly compared to how I was 4 months back.

This year I would rate myself around ~6.5 - 7 out of 10. Or maybe close to 7 as the breaking down of the patches introduced a confidence in me to how to really begin and what and how to think when you begin to appraoch a problem :)

What is remaining?

The Navigation Buttons whcih I will be implementing as it was already in the part of Monolith Patch so we have the code teh concept whcih we now have to adjust according to our new synchronous appraoch and more rich UI.

Then the other 35-40% of this project which was the Code-Auto Completion and Suggestion for the IDE and I have turst in myself that now I can approach this and can implement this.


And I cannot thank enough to my mentors Hossein, Prof. Lima, and specially Jonathan all the meetings which we had and the manuver which they helped me to take to reach this goal. But, it is more than that for me given my ADHD these 5 months have helped me to sit and focus on just one thing and being able to almost consistently do a single thing.

`