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

Allow language extensions to provide status information #129037

Closed
jrieken opened this issue Jul 20, 2021 · 94 comments
Closed

Allow language extensions to provide status information #129037

jrieken opened this issue Jul 20, 2021 · 94 comments
Assignees
Labels
api-finalization feature-request Request for new features or functionality languages-basic Basic language support issues on-release-notes Issue/pull request mentioned in release notes verification-needed Verification of issue is requested verified Verification succeeded
Milestone

Comments

@jrieken
Copy link
Member

jrieken commented Jul 20, 2021

Many language extensions add status bar entries for various information tidbits, like version, language server status, project etc. There is many inconsistencies for how this happens like alignment isn't always in sync with the language name or visibility isn't in sync with the active editor.

We should help extensions do a better job by adding a dedicated "language status" API, some kind of LanguageStatusProvider which we query whenever the editor changes. In its simplest form language status can be text, detail (supporting codicons and md), and severity.

@jrieken jrieken self-assigned this Jul 20, 2021
@jrieken jrieken added api-proposal feature-request Request for new features or functionality languages-basic Basic language support issues labels Jul 20, 2021
@jrieken jrieken modified the milestones: Backlog, July 2021 Jul 20, 2021
@jrieken
Copy link
Member Author

jrieken commented Jul 20, 2021

API sketch

enum LanguageStatusSeverity {
    Information,
    Warning,
    Error
}

declare class LanguageStatus {

    text: string;
    detail: string | MarkdownString;
    severity: LanguageStatusSeverity;

    constructor(text: string);
}

interface LanguageStatusProvider {
    provideLanguageStatus(): ProviderResult<LanguageStatus>;
}

declare namespace languages {
    export function registerLanguageStatusProvider(selector: DocumentSelector, provider: LanguageStatusProvider): Disposable;
}

@jrieken
Copy link
Member Author

jrieken commented Jul 20, 2021

fyi @mjbvz

@aeschli
Copy link
Contributor

aeschli commented Jul 20, 2021

Good stuff.
Not sure about text and detail, I would suggest to go with just message: string | MarkdownString.
I imagine this to be shown in a hover over the language mode status bar entry (e.g. 'JSON'). As there can potentially be multiple providers active for a given document, the hover would combine all the messages by concatenating them.

@mjbvz
Copy link
Contributor

mjbvz commented Jul 20, 2021

Looks promising. Here's the information we'd potentially like to show for JS/TS:

  • The current TS version (plus a way to switch versions)
  • The state of TS server.
    • Are we spinning up a full server? Right now we show initializing JS/TS language features progress in the status bar for this
    • Are we in partial only mode. If this is the case, we'd like to tell users that operations such as workspace symbol search may be incomplete
  • Potentially if logging is enabled and a quick way to jump to the log file

Additionally, it would be nice if we could customize the displayed information per-file instead of showing the same status for all files of given language. For JS/TS, this could be:

  • The tsconfig/jsconfig that the current file belongs to (and a way to quickly go to that config file)

If multiple extensions can contribute to the language status, it may also make sense to move some ESLint information into the language status


So my high level questions:

  • Should this API be per-file or per-language?
    • The current API uses a pull model but if we instead had a push model, we could leave this decision up to extensions like we do for status bar items
  • Should Language Status be a single item or an array of items?
  • Can multiple extensions contribute to a language status?

@egamma
Copy link
Member

egamma commented Jul 21, 2021

//CC @dbaeumer

@aeschli
Copy link
Contributor

aeschli commented Jul 21, 2021

Extensions can always take advantage of the existing vscode API to add additional status bar entries, with command handler, icons, colors, menus etc.
That's why I suggest that for the beginning we keep it simple and introduce a LanguageStatusProvider returning a MarkdownString that we can show as hover over the language selector. Thats something we currently can't do through API. Such API is also straightforward to adopt in LSP.

Keep it proposed for a while and I can adopt it in HTML, CSS and JSON to gain some UX experience

@jrieken
Copy link
Member Author

jrieken commented Jul 21, 2021

simple and introduce a LanguageStatusProvider returning a MarkdownString.

I think we need more than just a message because we need to show some kind of anchor in the status bar. I initially tried to hijack the language item for that but it has the "Change Language" message and command.

@jrieken
Copy link
Member Author

jrieken commented Jul 21, 2021

The current API uses a pull model but if we instead had a push model, we could leave this decision up to extensions like we do for status bar items

Yeah, it might simplify things and prevent repeated LanguageStatusProvider#onDidChange events. Generally we don't know when to ask for language status except when opening an editor. It just needs a nice way to target the files/scope of a certain status. The DocumentSelector could be enough as it support glob patterns and arity.

@jrieken
Copy link
Member Author

jrieken commented Jul 21, 2021

This is the updated (and implemented) proposal that uses the push model. I still looking for ways to eliminate the severity, e.g TypeScript being single-file only isn't an error nor warning but merely something "unexpected". Ideally, we find a way to express that, maybe a boolean like affectsUsage or limited

enum LanguageStatusSeverity {
Information = 0,
Warning = 1,
Error = 2
}
interface LanguageStatusItem {
selector: DocumentSelector;
text: string;
detail: string | MarkdownString
severity: LanguageStatusSeverity;
dispose(): void;
}
namespace languages {
export function createLanguageStatusItem(selector: DocumentSelector): LanguageStatusItem;
}

@mjbvz
Copy link
Contributor

mjbvz commented Jul 22, 2021

Just tested out the changes and like the push model

For the UI, if there are multiple statuses would we want to render them in a list? Perhaps something like:

|===============|
| First Title   |
| details       |
|---------------|
| Second Title  |
| details       |
|===============|
        ˅

A few other ideas:

  • Should the language status items have a priority, like we have the status bar items? This would help with ordering

  • Should we add a command to the language status item?

    • Right now you can run commands using MarkdownString, but it may be nicer if you could click the entire item to perform an action (like you can for status bar items)
  • Right now detail is used for tooltips. I wonder if we should have separate detail and tooltip fields. For the typescript version information for example, this might be:

    title =  "TypeScript Version"
    detail = "4.3.0"
    tooltip = "/path/to/tsdk"
    

@jrieken
Copy link
Member Author

jrieken commented Jul 22, 2021

Should we add a command to the language status item?

Yeah, 👍 for that - I believe the API will converge to be similar to the status bar API just with us controlling visibility, placement, and arity.

The ASCII art reminds me of how we do notifications and how they are behind the bell. So, one well-known icon which discloses more information. This would give it a clean & uniform look but might be too much hiding.

@jrieken
Copy link
Member Author

jrieken commented Aug 20, 2021

This is how it currently looks (UI and API)

Screen Shot 2021-08-20 at 17 10 48

  • Language status is text, detail, and command
  • Language status is part of a rich hover
  • There is the idea to make a language status pinnable to the status bar. This would make it easier to "migrate" users onto the new behaviour
  • It's still unclear how to anchor the status hover. Today, its the separate circle icon but a nicer icon and something that's combined with the language name is preferable

	enum LanguageStatusSeverity {
		Information = 0,
		Warning = 1,
		Error = 2
	}

	interface LanguageStatusItem {
		selector: DocumentSelector;
		severity: LanguageStatusSeverity;
		text: string;
		detail: string; // tooltip!
		command: Command | undefined;
		dispose(): void;
	}

	namespace languages {
		export function createLanguageStatusItem(selector: DocumentSelector): LanguageStatusItem;
	}

@daviddossett
Copy link
Contributor

👋 Here are a couple of additional explorations as I learn more about what's needed here. I've tried a few different versions using the discussion above as input. Any and all feedback welcome! cc @misolori

Option 1

Adds icon before language name

language-status-1

Option 2

Splits status into its own button. Adds counter for potentially multiple messages—not sure if that's needed but thought I'd hint at it here.

language-status-2

Option 3

Similar to option 1. Adds status icon and counter after language name.

language-status-3

@jrieken
Copy link
Member Author

jrieken commented Feb 21, 2022

To verify simply make sure that createLanguageStatusItem is in vscode.d.ts

@jrieken jrieken added the verification-needed Verification of issue is requested label Feb 21, 2022
@dbaeumer dbaeumer added the verified Verification succeeded label Feb 22, 2022
@jrieken jrieken added the on-release-notes Issue/pull request mentioned in release notes label Feb 24, 2022
@CsCherrYY
Copy link
Contributor

hi @jrieken, I'm trying to adopt this API in Java language support and it works well 👍. And I just find if we pin an item and we mark it busy, the spinning icon will appear in both language status item (the left one) and pinned item (the right one).

Screenshot 2022-03-15 163021

IMO it's a little duplicated and it's better to show the busy icon only in the language status item (the left one) to help users focus on the item. Does it make sense?

@jrieken
Copy link
Member Author

jrieken commented Mar 15, 2022

I agree. Can you please file a separate bug for that. Thanks

@CsCherrYY
Copy link
Contributor

@jrieken thanks for the swift reply! issue created here: #145115

@andyleejordan
Copy link
Member

Hey @CsCherrYY are you saying the left one isn't pinned? How did you get it to show up like that?

Here it is unpinned for us (it only shows up under the {} icon, and unpinned is the default, which is annoying our users):

Screen Shot 2022-03-15 at 9 49 49 AM

And after manually pinning it:

Screen Shot 2022-03-15 at 9 51 12 AM

@CsCherrYY
Copy link
Contributor

@andschwa The default in my case seems to be pinned. So in my screenshot, the default is only to show the left one, but no the right one.

But if you choose to unpin this item, the right one appears. It works when we just change the severity, text, etc. , but if we mark it busy, duplicate busy icons appear.

@CsCherrYY
Copy link
Contributor

Here is a suggestion about the visibility, sorry for disturbing. 🙂

We find abnormal severity (error or warning) for unpinned status (which is the default behavior) is not easy to find, compared to the pinned item.

pinned error:
image

unpinned error:
image

Users will find the status easier for the pinned item than the unpinned item, since the background is different. Can we consider changing the background color of the pinned item as well? (or another way to help users find this status)

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
api-finalization feature-request Request for new features or functionality languages-basic Basic language support issues on-release-notes Issue/pull request mentioned in release notes verification-needed Verification of issue is requested verified Verification succeeded
Projects
None yet
Development

No branches or pull requests