Skip to content

Commit

Permalink
Merge pull request #131264 from microsoft/joh/langStatus
Browse files Browse the repository at this point in the history
Language status items
  • Loading branch information
jrieken authored Aug 30, 2021
2 parents f146e5d + 5f3b7e1 commit 7443bb5
Show file tree
Hide file tree
Showing 14 changed files with 431 additions and 95 deletions.
4 changes: 4 additions & 0 deletions build/lib/i18n.resources.json
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,10 @@
"name": "vs/workbench/contrib/interactive",
"project": "vscode-workbench"
},
{
"name": "vs/workbench/contrib/languageStatus",
"project": "vscode-workbench"
},
{
"name": "vs/workbench/contrib/keybindings",
"project": "vscode-workbench"
Expand Down
4 changes: 2 additions & 2 deletions src/vs/base/browser/ui/hover/hover.css
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@
display: none;
}

.monaco-hover .hover-contents {
.monaco-hover .hover-contents:not(.html-hover-contents) {
padding: 4px 8px;
}

Expand Down Expand Up @@ -137,7 +137,7 @@
}

/** Spans in markdown hovers need a margin-bottom to avoid looking cramped: https://github.com/microsoft/vscode/issues/101496 **/
.monaco-hover .markdown-hover .hover-contents:not(.code-hover-contents) span {
.monaco-hover .markdown-hover .hover-contents:not(.code-hover-contents):not(.html-hover-contents) span {
margin-bottom: 4px;
display: inline-block;
}
Expand Down
2 changes: 1 addition & 1 deletion src/vs/base/browser/ui/iconLabel/iconLabel.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ export interface IIconLabelCreationOptions {
}

export interface IIconLabelMarkdownString {
markdown: IMarkdownString | string | undefined | ((token: CancellationToken) => Promise<IMarkdownString | string | undefined>);
markdown: IMarkdownString | string | HTMLElement | undefined | ((token: CancellationToken) => Promise<IMarkdownString | string | undefined>);
markdownNotSupportedFallback: string | undefined;
}

Expand Down
8 changes: 4 additions & 4 deletions src/vs/base/browser/ui/iconLabel/iconLabelHover.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ export function setupNativeHover(htmlElement: HTMLElement, tooltip: string | IIc
}
}

export function setupCustomHover(hoverDelegate: IHoverDelegate, htmlElement: HTMLElement, markdownTooltip: string | IIconLabelMarkdownString | undefined): IDisposable | undefined {
export function setupCustomHover(hoverDelegate: IHoverDelegate, htmlElement: HTMLElement, markdownTooltip: string | IIconLabelMarkdownString | HTMLElement | undefined): IDisposable | undefined {
if (!markdownTooltip) {
return undefined;
}
Expand Down Expand Up @@ -79,7 +79,7 @@ export function setupCustomHover(hoverDelegate: IHoverDelegate, htmlElement: HTM
hoverWidget?.dispose();
hoverWidget = hoverDelegate.showHover(hoverOptions);

const resolvedTooltip = (await tooltip(tokenSource.token)) ?? (!isString(markdownTooltip) ? markdownTooltip.markdownNotSupportedFallback : undefined);
const resolvedTooltip = (await tooltip(tokenSource.token)) ?? (!isString(markdownTooltip) && !(markdownTooltip instanceof HTMLElement) ? markdownTooltip.markdownNotSupportedFallback : undefined);

hoverWidget?.dispose();
hoverWidget = undefined;
Expand Down Expand Up @@ -119,8 +119,8 @@ export function setupCustomHover(hoverDelegate: IHoverDelegate, htmlElement: HTM
}


function getTooltipForCustom(markdownTooltip: string | IIconLabelMarkdownString): (token: CancellationToken) => Promise<string | IMarkdownString | undefined> {
if (isString(markdownTooltip)) {
function getTooltipForCustom(markdownTooltip: string | IIconLabelMarkdownString | HTMLElement): (token: CancellationToken) => Promise<string | IMarkdownString | HTMLElement | undefined> {
if (isString(markdownTooltip) || markdownTooltip instanceof HTMLElement) {
return async () => markdownTooltip;
} else if (isFunction(markdownTooltip.markdown)) {
return markdownTooltip.markdown;
Expand Down
9 changes: 6 additions & 3 deletions src/vs/vscode.proposed.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2873,15 +2873,18 @@ declare module 'vscode' {
}

interface LanguageStatusItem {
readonly id: string;
selector: DocumentSelector;
text: string;
detail: string | MarkdownString
severity: LanguageStatusSeverity;
name: string | undefined;
text: string;
detail: string;
command: Command | undefined;
dispose(): void;
}

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

//#endregion
Expand Down
6 changes: 3 additions & 3 deletions src/vs/workbench/api/common/extHost.api.impl.ts
Original file line number Diff line number Diff line change
Expand Up @@ -186,7 +186,7 @@ export function createApiFactoryAndRegisterActors(accessor: ServicesAccessor): I
const extHostMessageService = new ExtHostMessageService(rpcProtocol, extHostLogService);
const extHostDialogs = new ExtHostDialogs(rpcProtocol);
const extHostStatusBar = new ExtHostStatusBar(rpcProtocol, extHostCommands.converter);
const extHostLanguages = new ExtHostLanguages(rpcProtocol, extHostDocuments);
const extHostLanguages = new ExtHostLanguages(rpcProtocol, extHostDocuments, extHostCommands.converter);

// Register API-ish commands
ExtHostApiCommands.register(extHostCommands);
Expand Down Expand Up @@ -507,9 +507,9 @@ export function createApiFactoryAndRegisterActors(accessor: ServicesAccessor): I
checkProposedApiEnabled(extension);
return extHostLanguageFeatures.registerTypeHierarchyProvider(extension, selector, provider);
},
createLanguageStatusItem(selector: vscode.DocumentSelector): vscode.LanguageStatusItem {
createLanguageStatusItem(id: string, selector: vscode.DocumentSelector): vscode.LanguageStatusItem {
checkProposedApiEnabled(extension);
return extHostLanguages.createLanguageStatusItem(selector);
return extHostLanguages.createLanguageStatusItem(extension, id, selector);
}
};

Expand Down
56 changes: 43 additions & 13 deletions src/vs/workbench/api/common/extHostLanguages.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,19 +10,20 @@ import * as typeConvert from 'vs/workbench/api/common/extHostTypeConverters';
import { StandardTokenType, Range, Position, LanguageStatusSeverity } from 'vs/workbench/api/common/extHostTypes';
import Severity from 'vs/base/common/severity';
import { disposableTimeout } from 'vs/base/common/async';
import { IDisposable } from 'vs/base/common/lifecycle';
import { DisposableStore, IDisposable } from 'vs/base/common/lifecycle';
import { IExtensionDescription } from 'vs/platform/extensions/common/extensions';
import { CommandsConverter } from 'vs/workbench/api/common/extHostCommands';

export class ExtHostLanguages {

private readonly _proxy: MainThreadLanguagesShape;
private readonly _documents: ExtHostDocuments;

constructor(
mainContext: IMainContext,
documents: ExtHostDocuments
private readonly _documents: ExtHostDocuments,
private readonly _commands: CommandsConverter
) {
this._proxy = mainContext.getProxy(MainContext.MainThreadLanguages);
this._documents = documents;
}

getLanguages(): Promise<string[]> {
Expand Down Expand Up @@ -67,32 +68,58 @@ export class ExtHostLanguages {

private _handlePool: number = 0;

createLanguageStatusItem(selector: vscode.DocumentSelector): vscode.LanguageStatusItem {
createLanguageStatusItem(extension: IExtensionDescription, id: string, selector: vscode.DocumentSelector): vscode.LanguageStatusItem {

const handle = this._handlePool++;
const proxy = this._proxy;

const data: { selector: any, text: string, detail: string | vscode.MarkdownString, severity: vscode.LanguageStatusSeverity } = {
const data: Omit<vscode.LanguageStatusItem, 'dispose'> = {
selector,
id,
name: extension.displayName ?? extension.name,
severity: LanguageStatusSeverity.Information,
command: undefined,
text: '',
detail: '',
severity: LanguageStatusSeverity.Information,
};

let soonHandle: IDisposable | undefined;
let commandDisposables = new DisposableStore();
const updateAsync = () => {
soonHandle?.dispose();
soonHandle = disposableTimeout(() => {

commandDisposables.clear();

this._proxy.$setLanguageStatus(handle, {
id: `${extension.identifier.value}/${id}`,
name: data.name ?? extension.displayName ?? extension.name,
source: extension.displayName ?? extension.name,
selector: data.selector,
text: data.text,
message: typeof data.detail === 'string' ? data.detail : typeConvert.MarkdownString.from(data.detail),
severity: data.severity === LanguageStatusSeverity.Error ? Severity.Error : data.severity === LanguageStatusSeverity.Warning ? Severity.Warning : Severity.Info
label: data.text,
detail: data.detail,
severity: data.severity === LanguageStatusSeverity.Error ? Severity.Error : data.severity === LanguageStatusSeverity.Warning ? Severity.Warning : Severity.Info,
command: data.command && this._commands.toInternal(data.command, commandDisposables)
});
}, 0);
};

const result: vscode.LanguageStatusItem = {
dispose() {
commandDisposables.dispose();
soonHandle?.dispose();
proxy.$removeLanguageStatus(handle);
},
get id() {
return data.id;
},
get name() {
return data.name;
},
set name(value) {
data.name = value;
updateAsync();
},
get selector() {
return data.selector;
},
Expand Down Expand Up @@ -121,9 +148,12 @@ export class ExtHostLanguages {
data.severity = value;
updateAsync();
},
dispose() {
soonHandle?.dispose();
proxy.$removeLanguageStatus(handle);
get command() {
return data.command;
},
set command(value) {
data.command = value;
updateAsync();
}
};
updateAsync();
Expand Down
64 changes: 3 additions & 61 deletions src/vs/workbench/browser/parts/editor/editorStatus.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ import { ICursorPositionChangedEvent } from 'vs/editor/common/controller/cursorE
import { ConfigurationChangedEvent, IEditorOptions, EditorOption } from 'vs/editor/common/config/editorOptions';
import { ITextResourceConfigurationService } from 'vs/editor/common/services/textResourceConfigurationService';
import { ConfigurationTarget, IConfigurationService } from 'vs/platform/configuration/common/configuration';
import { deepClone, equals } from 'vs/base/common/objects';
import { deepClone } from 'vs/base/common/objects';
import { ICodeEditor, getCodeEditor } from 'vs/editor/browser/editorBrowser';
import { Schemas } from 'vs/base/common/network';
import { IPreferencesService } from 'vs/workbench/services/preferences/common/preferences';
Expand All @@ -50,11 +50,10 @@ import { IAccessibilityService, AccessibilitySupport } from 'vs/platform/accessi
import { IWorkbenchContribution } from 'vs/workbench/common/contributions';
import { IStatusbarEntryAccessor, IStatusbarService, StatusbarAlignment, IStatusbarEntry } from 'vs/workbench/services/statusbar/browser/statusbar';
import { IMarker, IMarkerService, MarkerSeverity, IMarkerData } from 'vs/platform/markers/common/markers';
import { STATUS_BAR_ERROR_ITEM_BACKGROUND, STATUS_BAR_ERROR_ITEM_FOREGROUND, STATUS_BAR_PROMINENT_ITEM_BACKGROUND, STATUS_BAR_PROMINENT_ITEM_FOREGROUND, STATUS_BAR_WARNING_ITEM_BACKGROUND, STATUS_BAR_WARNING_ITEM_FOREGROUND } from 'vs/workbench/common/theme';
import { ThemeColor, themeColorFromId } from 'vs/platform/theme/common/themeService';
import { STATUS_BAR_PROMINENT_ITEM_BACKGROUND, STATUS_BAR_PROMINENT_ITEM_FOREGROUND } from 'vs/workbench/common/theme';
import { themeColorFromId } from 'vs/platform/theme/common/themeService';
import { ITelemetryData, ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
import { SideBySideEditorInput } from 'vs/workbench/common/editor/sideBySideEditorInput';
import { ILanguageStatus, ILanguageStatusService } from 'vs/workbench/services/languageStatus/common/languageStatusService';
import { AutomaticLanguageDetectionLikelyWrongClassification, AutomaticLanguageDetectionLikelyWrongId, IAutomaticLanguageDetectionLikelyWrongData, ILanguageDetectionService } from 'vs/workbench/services/languageDetection/common/languageDetectionWorkerService';

class SideBySideEditorEncodingSupport implements IEncodingSupport {
Expand Down Expand Up @@ -182,7 +181,6 @@ class StateChange {
type StateDelta = (
{ type: 'selectionStatus'; selectionStatus: string | undefined; }
| { type: 'mode'; mode: string | undefined; }
| { type: 'languageStatus'; status: ILanguageStatus[] | undefined; }
| { type: 'encoding'; encoding: string | undefined; }
| { type: 'EOL'; EOL: string | undefined; }
| { type: 'indentation'; indentation: string | undefined; }
Expand All @@ -200,9 +198,6 @@ class State {
private _mode: string | undefined;
get mode(): string | undefined { return this._mode; }

private _status: ILanguageStatus[] | undefined;
get status(): ILanguageStatus[] | undefined { return this._status; }

private _encoding: string | undefined;
get encoding(): string | undefined { return this._encoding; }

Expand Down Expand Up @@ -248,13 +243,6 @@ class State {
}
}

if (update.type === 'languageStatus') {
if (!equals(this._status, update.status)) {
this._status = update.status;
change.languageStatus = true;
}
}

if (update.type === 'encoding') {
if (this._encoding !== update.encoding) {
this._encoding = update.encoding;
Expand Down Expand Up @@ -318,7 +306,6 @@ export class EditorStatus extends Disposable implements IWorkbenchContribution {
private readonly encodingElement = this._register(new MutableDisposable<IStatusbarEntryAccessor>());
private readonly eolElement = this._register(new MutableDisposable<IStatusbarEntryAccessor>());
private readonly modeElement = this._register(new MutableDisposable<IStatusbarEntryAccessor>());
private readonly statusElement = this._register(new MutableDisposable<IStatusbarEntryAccessor>());
private readonly metadataElement = this._register(new MutableDisposable<IStatusbarEntryAccessor>());
private readonly currentProblemStatus: ShowCurrentMarkerInStatusbarContribution = this._register(this.instantiationService.createInstance(ShowCurrentMarkerInStatusbarContribution));

Expand All @@ -330,7 +317,6 @@ export class EditorStatus extends Disposable implements IWorkbenchContribution {
private promptedScreenReader: boolean = false;

constructor(
@ILanguageStatusService private readonly languageStatusService: ILanguageStatusService,
@IEditorService private readonly editorService: IEditorService,
@IQuickInputService private readonly quickInputService: IQuickInputService,
@IModeService private readonly modeService: IModeService,
Expand Down Expand Up @@ -559,36 +545,6 @@ export class EditorStatus extends Disposable implements IWorkbenchContribution {
this.updateElement(this.modeElement, props, 'status.editor.mode', StatusbarAlignment.RIGHT, 100.1);
}

private updateStatusElement(status: ILanguageStatus[] | undefined): void {
if (!status || status.length === 0) {
this.statusElement.clear();
return;
}

const [first] = status;

let backgroundColor: ThemeColor | undefined;
let color: ThemeColor | undefined;
if (first.severity === Severity.Error) {
backgroundColor = themeColorFromId(STATUS_BAR_ERROR_ITEM_BACKGROUND);
color = themeColorFromId(STATUS_BAR_ERROR_ITEM_FOREGROUND);
} else if (first.severity === Severity.Warning) {
backgroundColor = themeColorFromId(STATUS_BAR_WARNING_ITEM_BACKGROUND);
color = themeColorFromId(STATUS_BAR_WARNING_ITEM_FOREGROUND);
}

const props: IStatusbarEntry = {
name: localize('status.editor.status', "Language Status"),
text: first.text,
ariaLabel: first.text,
tooltip: first.message,
backgroundColor,
color
};

this.updateElement(this.statusElement, props, 'status.editor.status', StatusbarAlignment.RIGHT, 100.05);
}

private updateMetadataElement(text: string | undefined): void {
if (!text) {
this.metadataElement.clear();
Expand Down Expand Up @@ -645,7 +601,6 @@ export class EditorStatus extends Disposable implements IWorkbenchContribution {
this.updateEncodingElement(this.state.encoding);
this.updateEOLElement(this.state.EOL ? this.state.EOL === '\r\n' ? nlsEOLCRLF : nlsEOLLF : undefined);
this.updateModeElement(this.state.mode);
this.updateStatusElement(this.state.status);
this.updateMetadataElement(this.state.metadata);
}

Expand Down Expand Up @@ -683,7 +638,6 @@ export class EditorStatus extends Disposable implements IWorkbenchContribution {
this.onScreenReaderModeChange(activeCodeEditor);
this.onSelectionChange(activeCodeEditor);
this.onModeChange(activeCodeEditor, activeInput);
this.onLanguageStatusChange(activeCodeEditor);
this.onEOLChange(activeCodeEditor);
this.onEncodingChange(activeEditorPane, activeCodeEditor);
this.onIndentationChange(activeCodeEditor);
Expand Down Expand Up @@ -717,10 +671,6 @@ export class EditorStatus extends Disposable implements IWorkbenchContribution {
this.onModeChange(activeCodeEditor, activeInput);
}));

this.activeEditorListeners.add(this.languageStatusService.onDidChange(() => {
this.onLanguageStatusChange(activeCodeEditor);
}));

// Hook Listener for content changes
this.activeEditorListeners.add(activeCodeEditor.onDidChangeModelContent((e) => {
this.onEOLChange(activeCodeEditor);
Expand Down Expand Up @@ -787,14 +737,6 @@ export class EditorStatus extends Disposable implements IWorkbenchContribution {
this.updateState(info);
}

private async onLanguageStatusChange(editorWidget: ICodeEditor | undefined): Promise<void> {
const update: StateDelta = { type: 'languageStatus', status: undefined };
if (editorWidget?.hasModel()) {
update.status = await this.languageStatusService.getLanguageStatus(editorWidget.getModel());
}
this.updateState(update);
}

private onIndentationChange(editorWidget: ICodeEditor | undefined): void {
const update: StateDelta = { type: 'indentation', indentation: undefined };

Expand Down
Loading

0 comments on commit 7443bb5

Please sign in to comment.