Overview

This is a proposal to change the workflow of selecting the context for data displayed in the standard debug views. These views include: Variables, Registers, Expressions, Memory, and possibly the Console views. This proposal builds on the previous efforts to improve multi-context debugging workflow: bug 145635 (Support for debug view pin & clone).

Goals

Allow user to switch the active context of a debug view without leaving the view.

Allow user to switch the active context of a debug view and without having to have the Launch view visible.

Allow user to have multiple instances of debug views open and showing data from different contexts side-by-side.

Avoid breaking any established UI paradigms with respect to views' interaction.

New UI Components and Workflow changes

Debug context selection dialog

A new selection dialog would allow user to choose the input context of a debug view. When the debug context selection dialog would open it would show a tree viewer where the top nodes are the participating debug context providers, and the sub-trees under the providers would be the contexts available for selection. Platform will provide the Launch Manager as the standard debug context provider, but others, such as Target Manager could also be shown. User would select the desired context in the dialog and press OK, to set the new input context to the view.

The debug context selection dialog should have a dedicated key binding and a tool-bar button or view menu item.

Link button in standard debug views

The standard debug views should all have a link toggle button on their toolbars. If the link button is down (default), the view context should follow the active window debug context as is does currently. If the link button is up, the input context of the debug the view should not change unless explicitly changed by the user. Selecting a new context using the debug context selection dialog would automatically un-link the view from window selection.

Content description in standard debug views

With the debug views able to select their own input context and with the Launch view possibly hidden or absent, it may be difficult to determine what is the current context of a given debug view. To address this problem, the content description of the view should be activated whenever a debug view is showing contents from a context that is different from the currently selected window context.

The content description of a view is currently limited to showing only text. To make it more useful for this feature, it should be extended to show an icon as well.

Multiple instances of standard debug views

Standard debug views should be configured to allow multiple instances of views to be opened. A toolbar button (or view menu item) should be added to easily open a new instance of the view. The memory view already supports this feature.

Setting active context for editors

When debugging, the editor is still the most important view on the screen. Just as in other debug views, the user needs to be able to focus to a different stack frame, thread, or process without leaving the editor. So just as in other debug views, user should be able to bring up the context selection dialog and jump to a different debug context. The status bar should display the current active context in the editor.

Deemphasizing the Launch view

Currently the debug view is essential to any debugging activity, because it drives the context of all other debug views. However, with the views and the editor being able to drive their own context, the Launch view should no longer be as critical to the standard work-flow. There are a few changes that should be made to better position the Launch view in the new workflow:

Move the run control actions to the global tool bar.

If the Launch view is closed, the editor should still react to breakpoint-hit and suspended events and open the appropriate source file.

Add a link button in the Launch view itself.

When depressed the Launch view should follow context from other views.

When up, the Launch view selection should not change, even for suspended events.

APIs

New context event: DebugContextEvent.CONTENT

In this feature proposal, views are be able to keep a given context as input even after that context is no longer active with a provider. The implication of this is that a given debug view can have an input context configured, which eventually gets terminated, removed, or otherwise becomes invalid. In this case, the debug view needs to be able to able to discover when a given context becomes invalid and change its input context as to avoid displaying stale data.

To facilitate this, the debug context providers should issue DebugContextEvent.STATE events for any context monitored by the given provider, not just for the active context. Also, the providers should issue a DebugContextEvent.CONTENT event whenever a sub-tree of a model changes in the given provider. The view can listen to these events and update as necessary.

IDebugContextProvider.getPresentationContext()

In a situation when:

a debug view is un-linked from a provider,

and it its input context is set to a given element which came from a given provider,

the input context becomes invalid due to a DebugContextEvent.CONTENT event,

the debug view should be able to use the IElementMementoProvider of the input context elements in order to find and select a new context, which is equivalent (has the same memento) to the one that became invalid. This would be useful, for example, to keep focused on a stack frame while stepping.

In order to implement this, the debug context provider should have a method to retrieve the IPresentationContext used by the provider, so that the debug view may construct IElementMenentoProvider requests properly.

Debug context selection dialog

Debug context mechanism allows for multiple context providers to be present, which are registered with the IDebugContextService.addContextProvider() call. However, the debug selection dialog should be able to operate even if the debug view and other debug context providers are not open. To address this, a new interface will be needed:

public interface IDebugContextRoot {
Object getRootElement();
}

To allow the lazy loading of IDebugContextRoot implementations, an extension point should also be provided to register context roots. When the context selection dialog is first opened the context root would be instantiated.

The root element returned by getRootElement() could then be used in the selection dialog to populate the contents of the dialog using the flexible hierarchy APIs (IElementContentProvider). After a selection is made in the dialog to set a view context, the debug view will need to install a IModelProxy on the root element of the context root and any children in order to generate proper debug context events. Registering model procies will allow the view to detect when the selected input context becomes invalid.

Alternative Design

One problem with the above design is that flexible hierarchy adapters for the elements originating from getRootElement() would need to support a new presentation context, coming from the selection dialog. This would mean a wide sweeping change to the existing model adapters.

To address this, the Debug context selection dialog could be split into two parts:

A drop-down selection control allowing user to choose the IDebugContextRoot

A tree viewer with the elements' hierarchy.

Another method would be added to the IDebugContextRoot: IPresentationContext getPresentationContext().

This design also has the added advantage in that the extension points providing IDebugContextRoot would not have to be invoked until the user chose the given root in the drop down.

IDebugContextService behavior changes

Better support for "part ID" context listeners

The standard debug views are listeners to the events coming from the window debug context service. Besides the input into the view, the active context returned by context service is used by actions which are contributed to the debug views. To control their context, debug views need to register their own providers with the window service using the IDebugContextService.addDebugContextProvider() method. View context listeners (e.g. view actions) can register themselves as listeners to context events using addDebugContextListener(IDebugContextListener listener, String partId). However, currently listeners registered this way will not receive any events if there is no provider registered for that ID. Since the views need to change between having their own provider and listening to the window context, I propose the following change to the debug context service:

Listeners registered using addDebugContextListener(IDebugContextListener listener, String partId) should receive active window context events if there is no provider registered with the given ID.

Default context provider

There should be a default context provider (provider with no part ID) registered in every window. This debug context provider would be responsible for the active context of the editors which implies the following change:

The debug view should no longer drive the source display, instead the default context provider should use the ISourceDisplay adapters in response to debug model events.

Finally, since the default context provider will be much more important, I propose another change:

Whenever in a view which does not have its own debug context provider, the active window context will be driven by the default context provider.

Comments

Please add your comments here. I will also summarize any email discussion here as well.

One feature which Eclipse lacks (and most other debuggers support) is the ability to view a variable in its own window. It would be nice if by double clicking (or some right click Action), a new variable view appeared for the variable. This could then be laid side by side with another variable view from another core so comparisons could be made.

The use cases for this are many: in the embedded C world there are often a number of large control structs plus a large number of other variables which may be interesting. Currently it's impossible to look at one variable which resides at the top of the view, while keeping an eye on another variable at the bottom of a view -- especially a problem if an expanded struct fills the entire view (the view collaping at random points during stepping doesn't help either...)! Your two variables view goes some way to redressing that problem, but it would be nice if the solution were more generic.

So in addition to being able to tie multiple views to various debug contexts, it would be nice too if the views were liberated further and could be used to display just a subset of the variables (akin to register groups -- but with fewer dialogs to create...).
--James Blackburn

I completely agree and I'm planning to write a second proposal that builds on this and includes functionality to create view filters and to manage sets of filters in logical groups. I would look forward to your comments on the second proposal as well. -Pawel

Using a dialog to select an active context sounds like an interesting approach. I would suggest to use a light weight dialog like the editor outline or inspect popup.

Q: What does it mean to activate "the content description of the view" whenever a debug view is showing contents from a context that is different from the currently selected window context? Does this mean to show the view title/label in bold (like when the console changes)? Or is the content description a new/seperate part in a view?

I simply meant to use the content description component of the standard view to show the current context of the view, because with views providing their own context it could get very confusing figuring out what is shown where. To save space I figured the content description could be de-activated when the view is linked with the window context. I'm not crazy about the UI presentation of the content description so I'd like to see if there's a way to improve it. -Pawel

I think it would make sense to move the "debug toolbar" to the window toolbar when no debug view is present. There could be realestate issues, as the toolbar is already quite full (and I'm not sure how much more full it is in other products).

Q: Should the toolbar only be in the launch view when the view is present?

It's true that some products cram a lot of stuff in to the toolbars, but mainly I was thinking of it as moving buttons from one place to another, without much gain or loss of UI real estate. But I realize that this is a big workflow change and perhaps the behavior you suggest or a preference driven toolbar in the launch view would be needed -Pawel

Q: I don't understand how unlinking the launch view works. I.e. to "follow the context in other views" only works if the other views are context providers. Otherwise, what does the lanuch view listen to for context changes? It should not be hardwired to any specific views.

The default context provider, which drives the context for the editor, would always be present. If the launch view was linked (by default) it would change its selection based on the active context from the default provider. If the launch view was un-linked it would register itself as a context provider and it would in turn drive the selection in the window. To preserve the existing workflow (that we all know and love) where changing the selection in Debug view opens the corresponding source, we could make the default provider also act like a linked view and have it automatically change its active context whenever an un-linked view gets focus. -Pawel

Q: As an implementation detail are you proposing that a view is assigned a special "context provider" when it becomes unlinked? I.e. a context provider that does not change contexts unless the context becomes invalid?

Yes, exactly. Although since I've written this I thought of some ways to simplify this further a bit. And when I get to prototyping, I will probably end up modifying more of the implementation details. -Pawel

Another way to address displaying content in the context selection dialog (i.e. since content providers do not know of this new context), would be to use the existing "debug view" context id. So the same hierarchy as in the debug view would be displayed. (I also think we need to support extensible content providers via an extension point, which would also help solve this problem... but to make all existing debuggers work in the dialog, using the "debug view" context is probably a simpler solution).

Yes, I totally agree. This is what I tried to get at with the "alternative design" which I thought of as I was writing this proposal. -Pawel

Having a default (invisible) context provider will allow to debug without the debug view. However, if there is a debug view present and it is "linked" to other views, I think that it should provide context for the window... otherwise it would be confusing to the user to understand where the active debug context is originating from.

I agree, the existing workflow needs to be preserved as is. I was thinking of achieving this by having the default provider always be "linked", and by having the launch view un-link automatically as soon as user changes the selection manually. I'm not sure if this would be sufficient though. This is probably the most tricky part of this whole design and it will likely need refinement. -Pawel

This will likely require that new context menu actions be added in the editor to allow user to bring up the popup dialog for switching context. I am not sure if there is a way to contribute this action globally. But does this mean it will likely force us to ask the editors that we depend on to implement the actions? What are we going to do if the user is using an editor that the debugger does not know about?

The default context provider would not be tied to any specific editor, therefore it would not require any editor contribution. I think of it as taking the launch view and separating out the part that reacts to model events and drives the ISourceDisplay adapters of the active context in order to activate the correct editor. This way the source may not even be an editor. If a debugger is using a view to display source (e.g. CDT), then a view could be activated showing current source location. I didn't really think much of the menu actions that would be needed to select a new context because I imagined using short-cut keys most of the time, but I guess it would make most sense to add the "switch debug context" action to the Navigate menu -Pawel

Re: Unlinking the Launch View

I am not sure I understand why the Launch view needs to be unlink. My understanding is that is there a global default context provider for the window and this is where the Launch View is linked to. By unlinking, are you trying to allow the Debug View to override the context provided by the default context provider? In this case, we can maintain the workflow that everyone currently loves?

I'll say up front that this functionality will take some experimentation to get it right. But what I would like to achieve is to make the Debug view less essential to the debug workflow. Following from this, the debug view would be just another view that listens to the active window selection, and like other views, it would un-link when the user manually changed the context within a view. The problem with this is that this would break the existing workflow, so perhaps the idea of treating the debug view like any other view is not going to work. So I would like to leave this a bit open ended and see how it comes together during implementation -Pawel

Re: Global Debug Toolbar

We talked about this briefly in the meeting. Some concerns include real-estate and how we can migrate existing contributions to the toolbar. Since there is also a global Run Menu that contains all the default debug actions, I am wondering if having a global toolbar menu is redundant. Do we really need both?

My other thoughts to this is the possibility of having a floating toolbar, and the user can put it anywhere desired.

I think a debug toolbar is something that most users expect to see, whether it's in the launch view or in the global toolbar area. For me this is also a part of de-emphesizing the launch view in the standard workflow. -Pawel

Re: Who drives the default context provider?

The default context provider is not hooked to any view. I understand that the debug model will provider context to the default context provider. However, how can we control if a debug element should become the active debug context through the default context provider? For example, in the case of a multi-threaded applications, multiple threads can get suspended at the same time. The current behavior is to select top stackframe from the first suspended thread. This stackframe becomes the current debug context. When other threads are suspended, selection does not change and their top stackframes are not set as current debug context. Since there is no view to drive such interactions, how can a debug model control if a certain debug element be considered the current debug context?

The default context provider would react to the model selection events just like the launch view view does now. So even if the launch view was closed, if a thread suspended, the corresponding stack frame would become active. And the IModelSelectionPolicy adapter would be used by the default context provider rather than by the launch view. -Pawel

More comments. ~Darin Wright (10/23/2007)

Reviewing this proposal again, I think what's missing is the higher level goal. I believe the higher level goal is to be able to have sets of debug views linked to a specific context, and to be able to have different debug contexts (e.g. cores within a session) have different sets of views that can be placed side by side.

I think a problem with this proposal is that it places a heavy burder on the user to manage views. For example, they must manually unlink and pin views to a specific context. Then, once a context is stale it's not clear how to cleanup the view (i.e. is it left floating?), and how to capture/reuse a "view configuration" in a later debug session now that time has been spent setting it up. Can the user set up a view configuration before launching (i.e. in a launch configuration)?

Note that the debug platform already has a mechanism for grouping views for a particular kind of debug session. For example, a Java debug session has a certain set of views assocaited with it, and when the user selects a Java stack frame, the relevant views are brought to the front/opened. There are extension points to support this: contextViewBindings and debugModelContextBindings. Basically, we tie a "context" to a set of views and bind a debug model to a "context".

I wonder if it would be simpler to enhance the existing support to allow for a "new set" (more instances) of the same views to be opened for a debug session. This would leverage the existing support any may help achieve the higher level goal (a dedicated group of related views for a debug session) with less steps/burden placed on the user. I could also see this sort of support appearing in a launch config - i.e. as a check box to use a new set of views, and perhaps which views they'd like to see.

More comments from Samantha Chan (10/23/2007)

Re: Select Debug Context Dialog from View or Editor

The dialog is to show different available context that is available for the user to switch between. The dialog will have a drop down to show available context root. A context root contains available context. (e.g I assume the context root is the root in the Debug View where it is the Launch Manager.) Having a dialog to display available context is not scalable, especially in parallel computing environment where we can have thousands of processes and threads. We need a way disable this feature all together to avoid the scalability problems. Or, we need a way to override the control used to displayed the context to allow us to plug in fancier UIs to show context in a scalable manner.

Re: De-centralization of the Launch View

The proposal suggested that a default context provider is created for a window. The default context provider is not tied to any view. The Launch View is simply a listener to the default context provider. This allows the Debug Perspective to operate without the presence of the Launch View. The concern here is that without having a view tied to the default context provider, it is extremely confusing to figure out what the current debug context is. I agree that having another "kind" of view to drive the active debug context is a good idea, but not having a view at all can cause usability problems. For example, if the user is debugging a multi-threaded application, and the user is suspended at Thread A, and debugging. Meanwhile, another thread, Thread B, is suspended. Without a view to indicate that something else is suspended, how does the user know that another context has become available? What are some of the reasons why we do not want a view to drive the active debug context? Why is having a view opened to drive the current context problematic?

Re: Global Debug Actions Toolbar

Since the Launch View does not need to be present all the time, actions from the Launch View's toolbar need to become global. This causes a couple problems for us:

- Real-estate on the global toolbar - this makes the global toolbar more cluttered.

- When invoking action on the toolbar, how does the user know what context the action is invoked on. e.g. if I press resume, which thread am I resuming, without having the Launch View tells me which thread is in focus?

We also believe that this is a side effect to not having a view to drive debug context. If a view is always present, then there will be no need for global debug actions toolbar.

Re: Changes in the workflow

As indicated in the proposal, this means that debugging workflow can be changed significantly. Do we have enough time to get this right in the 3.4 timeframe since the changes are so drastic. We have many debuggers built on top of the platform. We are concerned that the changes in workflow can cause a lot of confusion with our existing users. One of our requirements is that this work item should not break existing debug adapters. Existing debug adapters should just work without much migration work involved.

If the client has registered with a partID that does not exist, the proposal is to change the behavior to have the listener get a context events from the default context provider. In my opinion, when the client has specified a part id with the listener registration, the client intends to filter out events from views that it does not care about. Otherwise, the client could have registered without the part id. Changing this behavior could break existing clients and introduce compatibility issues.