Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add output.showQuietly to stop extensions activating Output view (fix #105270) #205225

Open
wants to merge 31 commits into
base: main
Choose a base branch
from

Conversation

gjsjohnmurray
Copy link
Contributor

This PR fixes #105270

When the new output.showQuietly setting is true calls to OutputChannel.show or LogOutputChannel.show when Output view is not visible will produce a silent notification rather than showing the view.

Like all silent notifications this will add a dot to the bell icon at the right-hand end of the status bar. Clicking on this will show the notification which includes a button to show the Output view and the channel.

@gjsjohnmurray
Copy link
Contributor Author

/assign @sandy081

Please consider this. Feedback welcome.

@sandy081
Copy link
Member

I am wondering why this is output only feature. An extension can open any view in the panel for eg., terminal and should we have a setting per view? Please consider a general solution.

@sandy081
Copy link
Member

CC @sbatten

@sandy081 sandy081 assigned sbatten and unassigned sandy081 Feb 19, 2024
@gjsjohnmurray
Copy link
Contributor Author

@sandy081 AFAIK these are the API classes with methods an extension can use and which could cause a view container to change what it is presenting to the user:

  • LogOutputChannel.show
  • OutputChannel.show
  • Terminal.show
  • TreeView.reveal
  • WebviewView.show

I didn't find any built-in commands that could have this kind of effect.

My PR currently addresses the first two, which both act on the Output view.

One idea for a generalized approach would be a workbench.view.showQuietly setting

"workbench.view.showQuietly": {
  "workbench.panel.output": true, // the PR's current extent
  "terminal": true,
  "foo.bar.tree": true,
  "foo.bar.webview": true,
  ...
}

What do you think?

@gjsjohnmurray
Copy link
Contributor Author

Research: existing OSS view ids

image

@sandy081
Copy link
Member

I would ask @sbatten for his opinion here.

@jstm88
Copy link

jstm88 commented Feb 22, 2024

  • LogOutputChannel.show
  • OutputChannel.show
  • Terminal.show
  • TreeView.reveal
  • WebviewView.show

It certainly makes sense that some of these could be covered as well, as noted by the other feature request.

One thing: I'm not sure if TreeView here refers to the Explorer or the Outline (the user facing UI doesn't refer to a Tree View as far as I can tell). But I am reminded of my keybinding for workbench.files.action.showActiveFileInExplorer. It's directly triggered through VS Code (not an extension) so it shouldn't be affected, but just something to keep in mind depending on how the logic for that view gets triggered. I would assume other direct triggers like Ctrl+~ for the Terminal would also be exempt if any of these were to have a similar quiet option added.

Copy link

@jstm88 jstm88 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code looks good to me. Not sure if my approval counts for anything here but I'd like to move this along if I can. :)

EDIT: As I suspected mine doesn't count for collaborator approvals. Really hope the VS Code team doesn't ignore this like they've ignored the years of bug reports leading up to it. 🙄

@gjsjohnmurray
Copy link
Contributor Author

In February @sandy081 wrote:

I would ask @sbatten for his opinion here.

@sbatten what do you think?

@benibenj
Copy link
Contributor

benibenj commented Jul 11, 2024

Sorry for the wait @gjsjohnmurray. As this is adding a new Setting, I'd like to make sure this is actually something we should be fixing as it is actually caused by extensions. The issue currently only mentions one extension and the output view. If this is the main problem then we should make sure the problem is solved by the extension. If the problem needs to be in core, we need to understand if it is an output problem or a view revealing problem. I'll continue the conversation in the issue first.

@stewartadam
Copy link
Member

It's definitely an issue with multiple extensions - it's particularly frustrating with dev containers as each extension initializes with slightly different timing and the net user experience is stolen focus to open the Output pane several times.

I think more broadly, trying to fix a distributed problem is going to perpetuate this bad UX.

I don't want anything stealing focus out of my editor, and I'd love a setting to enforce that instead of trying to convince a half dozen extension maintainers to do the right thing 😅

@phaberest
Copy link

@gjsjohnmurray I would suggest to rebase and cleanup the commits instead of adding all those merge commits, apart from that it looks good. I hope a compromise will be found and wish this gets merged 🙌🏻

@gjsjohnmurray
Copy link
Contributor Author

@phaberest GH tells me it can't be rebased due to conflicts.

Copy link
Contributor

@benibenj benibenj left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We are still unsure if this should be only for the output view or a general solution for all kind of view revealing. Let's start off with having this for the output view only and we can expand it to all if needed. As this should only block extensions from revealing, lets move the logic a layer up.

src/vs/workbench/contrib/output/browser/outputServices.ts Outdated Show resolved Hide resolved
src/vs/workbench/contrib/output/browser/outputServices.ts Outdated Show resolved Hide resolved
@gjsjohnmurray
Copy link
Contributor Author

@benibenj I will try and work on this next week.

@gjsjohnmurray
Copy link
Contributor Author

@benibenj I have pushed changes to implement what you suggested. I put the indicator next to the notifications bell because it serves a similar purpose and users are probably used to keeping half an eye on that corner.

image

Hovered:

image

@benibenj benibenj added this to the November 2024 milestone Nov 19, 2024
@gjsjohnmurray
Copy link
Contributor Author

gjsjohnmurray commented Nov 19, 2024

Here's one way to test this PR:

  1. Clone microsoft/vscode-extension-samples
  2. Open its task-provider-sample folder
  3. Follow its README instructions to init, build and run it
  4. When it is running in EH open a fresh empty folder.
  5. In it create a file named Rakefile and insert an invalid line (e.g. just the text invalid)
  6. Close your Panel
  7. From Terminal menu choose Run Task...
  8. Wait about 5 seconds at the quickpick
  9. Observe that your Panel appears, the Output tab displays, and the Rake Auto Detection channel contributed by the extension reports your Rakefile error

Now build VS Code from this PR's branch, run it, and follow these steps:

  1. Open your task-provider-sample folder
  2. Run that
  3. Open the folder you created in step 4 above
  4. Continue from step 6 above.

Set output.showQuietly true for your testing folder, then reload and repeat from step 6. Instead of Panel appearing after 5 seconds you should see the new indicator on the status bar.

@gjsjohnmurray
Copy link
Contributor Author

@benibenj does this PR still stand a chance of being approved in time for next week's edngame?

Copy link
Contributor

@benibenj benibenj left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Tested it, I like the way it behaves. I think it is likely that this will also be adopted to other views so I wonder if we should already consider using a setting name which is not specific to output. Maybe "workbench.view.showQuietly" as you suggested before. It could be boolean for now and then later be expanded to boolean | object (obect with view IDs)

private readonly _configurationService: IConfigurationService;
private readonly _statusbarService: IStatusbarService;

private _outputStatusItem: IStatusbarEntryAccessor | undefined;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How about making this a MutableDisposable of type IStatusbarEntryAccessor and registering it here so it gets disposed when MainThreadOutputService gets disposed.


this._proxy = extHostContext.getProxy(ExtHostContext.ExtHostOutputService);

const setVisibleChannel = () => {
const visibleChannel = this._viewsService.isViewVisible(OUTPUT_VIEW_ID) ? this._outputService.getActiveChannel() : undefined;
this._proxy.$setVisibleChannel(visibleChannel ? visibleChannel.id : null);
this._outputStatusItem?.dispose();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This would then be this._outputStatusItem.value = undefined;

Comment on lines 79 to 107
public async $reveal(channelId: string, preserveFocus: boolean): Promise<void> {
const channel = this._getChannel(channelId);
if (channel) {
this._outputService.showChannel(channel.id, preserveFocus);
if (this._viewsService.isViewVisible(OUTPUT_VIEW_ID) || !this._configurationService.getValue('output.showQuietly')) {
this._outputService.showChannel(channel.id, preserveFocus);
return;
}

// Show status bar indicator
const statusProperties: IStatusbarEntry = {
name: localize('status.showOutput', "Show Output"),
text: '$(output)',
ariaLabel: localize('status.showOutputAria', "Show {0} Output Channel", channel.label),
command: `workbench.action.output.show.${channel.id}`,
tooltip: localize('status.showOutputTooltip', "Show {0} Output Channel", channel.label),
kind: 'prominent'
};
if (!this._outputStatusItem) {
this._outputStatusItem = this._statusbarService.addEntry(
statusProperties,
'status.showOutput',
StatusbarAlignment.RIGHT,
{ id: 'status.notifications', alignment: StatusbarAlignment.LEFT },
);
} else {
this._outputStatusItem.update(statusProperties);
}
}
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just for readability:

  • Can we do if (!channel) and return to remove nesting
  • Have a private method called _showChannelQuietly(channel)
  • Change the if statement to if (!this._viewsService.isViewVisible(OUTPUT_VIEW_ID) && this._configurationService.getValue('output.showQuietly')) then call this._showChannelQuietly(channel) and return and have this._outputService.showChannel at the end outside any if statement

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Add an option to prevent side panel from opening