Layout, and what a saved desktop does
The question I left open — whether an incoming provider's window inherits where
the outgoing one was sitting — and your saved-desktop problem are the same
missing concept. The IDE has layout per window id, and nothing that represents
"the debug terminal, whichever one that currently is".
So: a slot. Providers keep their own window ids, as you said they must —
different providers have different numbers of windows, and one may have none.
What gets added is that a provider registers its window into a named slot, and
the IDE stores a layout against the slot as well as against the ids. Lookup when
a slot window is created is: the provider's own override, then the slot layout,
then the provider's default.
Seeded or tracked: I would track. Whenever the active provider's slot window is
moved or resized, that becomes the slot layout. Seeding only on first show means
the providers diverge again after one switch, which is the behaviour I have now,
just postponed. Tracking gives "the debug terminal stays where I put it" across a
provider change, which is the thing the single slot is for.
The override is for a provider that genuinely cannot live in the inherited
geometry. I would make it a minimum size rather than a boolean — the slot layout
applies, clamped to what the provider says it needs — with a hard "ignore the
slot" flag as the escape hatch for whatever I have not thought of.
Two cases that would otherwise misbehave quietly:
- A provider with no window must not write to the slot layout when it is
selected. Otherwise switching to a task-icon-only provider and back loses the
position.
- A provider with several windows applies the slot to one primary window. The
rest are ordinary windows with ordinary ids, stored as such.
Saved desktops
The desktop case then falls out of it. The IDE knows which window ids are
registered into the terminal slot. When a desktop is applied, a window belonging
to that slot whose provider is not the active one is suppressed, and the active
provider's window opens instead, using the layout the desktop stored for the
slot.
Your F9 sequence becomes: the desktop says "terminal slot, open, bottom right",
the selection says which one, and the console that is no longer active never
appears.
It also migrates for free, which is the part I like. Existing desktops contain
IdeDbgConsole. If the built-in registers into the slot like any other provider,
those desktops read as "slot open, here" with no migration step, and their stored
geometry becomes the initial slot layout.
The cost, so it is on the table now rather than found later: desktops become
provider-agnostic. Someone who wants a saved desktop pinned to one specific
provider cannot express that. I think it is the right trade — a desktop is a
layout, not a debugger configuration — but it is a decision, and not obviously
mine to make.
I will take the testing on this, docked and undocked, saved desktops included.
Naming
Better naming ideas welcome.
Your own reasoning argues against Class as much as against ClassName: it is not
the class name, it is not only for XML, and the second segment may be a
meaningful replacement rather than a class at all. GetPlugInId and FindByPlugInId
say what it is and survive all three. If you want the format visible in the name,
GetQualifiedId.
On the assertion pattern: [a-z_]{5,} rules out digits and any package name under
five characters, which will catch somebody. Per segment I would allow
[A-Za-z_][A-Za-z0-9_]* and compare case-insensitively on lookup — a stored id
differing only in case should not read as a different plugin. And whether the
third segment is permitted at all is worth settling now rather than discovering
it when someone ships one.
Channel
Unknown over Merged, agreed. Merged capture is one cause, and a backend that
simply never distinguishes is another, so Unknown is the honest name for both:
the backend did not tell us. I would not add a separate value for genuinely
merged — no provider can do anything with the difference.
TLazDbgTargetIoChannel = (Unknown, StdOut, StdErr), in LazDebuggerIntf, with the
backend sending it eventually. Agreed on all three.
The smaller points
ILazDbgIdePlugIn — yes, shorter wins.
Supports as a superset at class level now, with a second query on the instance
once the debugger starts, works for me. The instance-time decision is the one
that matters, and it is the one that can be reported to the user properly.
CreateCopy I would keep, even with one instance per class. It is not for copying
providers — it is for Cancel in the options dialog. The settings frame edits
something, and Cancel has to discard that without the live object having been
touched. That is what the value formatter uses it for as well. On the base,
returning the base interface.