Skip to content

Commit

Permalink
docs: 📝 add documentation for the HighlightedLabel widget
Browse files Browse the repository at this point in the history
Related-to: #124652
  • Loading branch information
joaomoreno committed Nov 11, 2021
1 parent bb6f91b commit cf35554
Show file tree
Hide file tree
Showing 13 changed files with 73 additions and 36 deletions.
53 changes: 45 additions & 8 deletions src/vs/base/browser/ui/highlightedlabel/highlightedLabel.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,39 +7,72 @@ import * as dom from 'vs/base/browser/dom';
import { renderLabelWithIcons } from 'vs/base/browser/ui/iconLabel/iconLabels';
import * as objects from 'vs/base/common/objects';

/**
* A range to be highlighted.
*/
export interface IHighlight {
start: number;
end: number;
extraClasses?: string;
extraClasses?: string[];
}

export interface IOptions {

/**
* Whether
*/
readonly supportIcons?: boolean;
}

/**
* A widget which can render a label with substring highlights, often
* originating from a filter function like the fuzzy matcher.
*/
export class HighlightedLabel {

private readonly domNode: HTMLElement;
private text: string = '';
private title: string = '';
private highlights: IHighlight[] = [];
private supportIcons: boolean;
private didEverRender: boolean = false;

constructor(container: HTMLElement, private supportIcons: boolean) {
this.domNode = document.createElement('span');
this.domNode.className = 'monaco-highlighted-label';

container.appendChild(this.domNode);
/**
* Create a new {@link HighlightedLabel}.
*
* @param container The parent container to append to.
*/
constructor(container: HTMLElement, options?: IOptions) {
this.supportIcons = options?.supportIcons ?? false;
this.domNode = dom.append(container, dom.$('span.monaco-highlighted-label'));
}

/**
* The label's DOM node.
*/
get element(): HTMLElement {
return this.domNode;
}

/**
* Set the label and highlights.
*
* @param text The label to display.
* @param highlights The ranges to highlight.
* @param title An optional title for the hover tooltip.
* @param escapeNewLines Whether to escape new lines.
* @returns
*/
set(text: string | undefined, highlights: IHighlight[] = [], title: string = '', escapeNewLines?: boolean) {
if (!text) {
text = '';
}

if (escapeNewLines) {
// adjusts highlights inplace
text = HighlightedLabel.escapeNewLines(text, highlights);
}

if (this.didEverRender && this.text === text && this.title === title && objects.equals(this.highlights, highlights)) {
return;
}
Expand All @@ -59,6 +92,7 @@ export class HighlightedLabel {
if (highlight.end === highlight.start) {
continue;
}

if (pos < highlight.start) {
const substring = this.text.substring(pos, highlight.start);
children.push(dom.$('span', undefined, ...this.supportIcons ? renderLabelWithIcons(substring) : [substring]));
Expand All @@ -67,9 +101,11 @@ export class HighlightedLabel {

const substring = this.text.substring(highlight.start, highlight.end);
const element = dom.$('span.highlight', undefined, ...this.supportIcons ? renderLabelWithIcons(substring) : [substring]);

if (highlight.extraClasses) {
element.classList.add(highlight.extraClasses);
element.classList.add(...highlight.extraClasses);
}

children.push(element);
pos = highlight.end;
}
Expand All @@ -80,16 +116,17 @@ export class HighlightedLabel {
}

dom.reset(this.domNode, ...children);

if (this.title) {
this.domNode.title = this.title;
} else {
this.domNode.removeAttribute('title');
}

this.didEverRender = true;
}

static escapeNewLines(text: string, highlights: IHighlight[]): string {

let total = 0;
let extra = 0;

Expand Down
6 changes: 3 additions & 3 deletions src/vs/base/browser/ui/iconLabel/iconLabel.ts
Original file line number Diff line number Diff line change
Expand Up @@ -118,7 +118,7 @@ export class IconLabel extends Disposable {
}

if (options?.supportDescriptionHighlights) {
this.descriptionNodeFactory = () => new HighlightedLabel(dom.append(this.descriptionContainer.element, dom.$('span.label-description')), !!options.supportIcons);
this.descriptionNodeFactory = () => new HighlightedLabel(dom.append(this.descriptionContainer.element, dom.$('span.label-description')), { supportIcons: !!options.supportIcons });
} else {
this.descriptionNodeFactory = () => this._register(new FastLabelNode(dom.append(this.descriptionContainer.element, dom.$('span.label-description'))));
}
Expand Down Expand Up @@ -281,7 +281,7 @@ class LabelWithHighlights {
if (!this.singleLabel) {
this.container.innerText = '';
this.container.classList.remove('multiple');
this.singleLabel = new HighlightedLabel(dom.append(this.container, dom.$('a.label-name', { id: options?.domId })), this.supportIcons);
this.singleLabel = new HighlightedLabel(dom.append(this.container, dom.$('a.label-name', { id: options?.domId })), { supportIcons: this.supportIcons });
}

this.singleLabel.set(label, options?.matches, undefined, options?.labelEscapeNewLines);
Expand All @@ -299,7 +299,7 @@ class LabelWithHighlights {
const id = options?.domId && `${options?.domId}_${i}`;

const name = dom.$('a.label-name', { id, 'data-icon-label-count': label.length, 'data-icon-label-index': i, 'role': 'treeitem' });
const highlightedLabel = new HighlightedLabel(dom.append(this.container, name), this.supportIcons);
const highlightedLabel = new HighlightedLabel(dom.append(this.container, name), { supportIcons: this.supportIcons });
highlightedLabel.set(l, m, undefined, options?.labelEscapeNewLines);

if (i < label.length - 1) {
Expand Down
2 changes: 1 addition & 1 deletion src/vs/base/test/browser/highlightedLabel.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ suite('HighlightedLabel', () => {
let label: HighlightedLabel;

setup(() => {
label = new HighlightedLabel(document.createElement('div'), true);
label = new HighlightedLabel(document.createElement('div'), { supportIcons: true });
});

test('empty label', function () {
Expand Down
2 changes: 1 addition & 1 deletion src/vs/editor/contrib/gotoSymbol/peek/referencesTree.ts
Original file line number Diff line number Diff line change
Expand Up @@ -167,7 +167,7 @@ class OneReferenceTemplate {
readonly label: HighlightedLabel;

constructor(container: HTMLElement) {
this.label = new HighlightedLabel(container, false);
this.label = new HighlightedLabel(container);
}

set(element: OneReference, score?: FuzzyScore): void {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -553,7 +553,7 @@ class TextEditElementTemplate {
this._icon = document.createElement('div');
container.appendChild(this._icon);

this._label = new HighlightedLabel(container, false);
this._label = new HighlightedLabel(container);
}

dispose(): void {
Expand Down Expand Up @@ -582,8 +582,8 @@ class TextEditElementTemplate {
value += element.inserting;
value += element.suffix;

let selectHighlight: IHighlight = { start: element.prefix.length, end: element.prefix.length + element.selecting.length, extraClasses: 'remove' };
let insertHighlight: IHighlight = { start: selectHighlight.end, end: selectHighlight.end + element.inserting.length, extraClasses: 'insert' };
let selectHighlight: IHighlight = { start: element.prefix.length, end: element.prefix.length + element.selecting.length, extraClasses: ['remove'] };
let insertHighlight: IHighlight = { start: selectHighlight.end, end: selectHighlight.end + element.inserting.length, extraClasses: ['insert'] };

let title: string | undefined;
let { metadata } = element.edit.textEdit;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,7 @@ export class DocumentSymbolGroupRenderer implements ITreeRenderer<OutlineGroup,
const labelContainer = dom.$('.outline-element-label');
container.classList.add('outline-element');
dom.append(container, labelContainer);
return new DocumentSymbolGroupTemplate(labelContainer, new HighlightedLabel(labelContainer, true));
return new DocumentSymbolGroupTemplate(labelContainer, new HighlightedLabel(labelContainer));
}

renderElement(node: ITreeNode<OutlineGroup, FuzzyScore>, _index: number, template: DocumentSymbolGroupTemplate): void {
Expand Down
2 changes: 1 addition & 1 deletion src/vs/workbench/contrib/debug/browser/baseDebugView.ts
Original file line number Diff line number Diff line change
Expand Up @@ -149,7 +149,7 @@ export abstract class AbstractExpressionsRenderer implements ITreeRenderer<IExpr
const expression = dom.append(container, $('.expression'));
const name = dom.append(expression, $('span.name'));
const value = dom.append(expression, $('span.value'));
const label = new HighlightedLabel(name, false);
const label = new HighlightedLabel(name);

const inputBoxContainer = dom.append(expression, $('.inputBoxContainer'));

Expand Down
6 changes: 3 additions & 3 deletions src/vs/workbench/contrib/debug/browser/callStackView.ts
Original file line number Diff line number Diff line change
Expand Up @@ -513,7 +513,7 @@ class SessionsRenderer implements ICompressibleTreeRenderer<IDebugSession, Fuzzy
dom.append(session, $(ThemeIcon.asCSSSelector(icons.callstackViewSession)));
const name = dom.append(session, $('.name'));
const stateLabel = dom.append(session, $('span.state.label.monaco-count-badge.long'));
const label = new HighlightedLabel(name, false);
const label = new HighlightedLabel(name);
const actionBar = new ActionBar(session, {
actionViewItemProvider: action => {
if (action instanceof MenuItemAction) {
Expand Down Expand Up @@ -600,7 +600,7 @@ class ThreadsRenderer implements ICompressibleTreeRenderer<IThread, FuzzyScore,
const thread = dom.append(container, $('.thread'));
const name = dom.append(thread, $('.name'));
const stateLabel = dom.append(thread, $('span.state.label.monaco-count-badge.long'));
const label = new HighlightedLabel(name, false);
const label = new HighlightedLabel(name);
const actionBar = new ActionBar(thread);
const elementDisposable: IDisposable[] = [];

Expand Down Expand Up @@ -656,7 +656,7 @@ class StackFramesRenderer implements ICompressibleTreeRenderer<IStackFrame, Fuzz
const fileName = dom.append(file, $('span.file-name'));
const wrapper = dom.append(file, $('span.line-number-wrapper'));
const lineNumber = dom.append(wrapper, $('span.line-number.monaco-count-badge'));
const label = new HighlightedLabel(labelDiv, false);
const label = new HighlightedLabel(labelDiv);
const actionBar = new ActionBar(stackFrame);

return { file, fileName, label, lineNumber, stackFrame, actionBar };
Expand Down
4 changes: 2 additions & 2 deletions src/vs/workbench/contrib/debug/browser/replViewer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ export class ReplEvaluationInputsRenderer implements ITreeRenderer<ReplEvaluatio
renderTemplate(container: HTMLElement): IReplEvaluationInputTemplateData {
dom.append(container, $('span.arrow' + ThemeIcon.asCSSSelector(debugConsoleEvaluationInput)));
const input = dom.append(container, $('.expression'));
const label = new HighlightedLabel(input, false);
const label = new HighlightedLabel(input);
return { label };
}

Expand Down Expand Up @@ -260,7 +260,7 @@ export class ReplRawObjectsRenderer implements ITreeRenderer<RawObjectReplElemen

const expression = dom.append(container, $('.output.expression'));
const name = dom.append(expression, $('span.name'));
const label = new HighlightedLabel(name, false);
const label = new HighlightedLabel(name);
const value = dom.append(expression, $('span.value'));

return { container, expression, name, label, value };
Expand Down
2 changes: 1 addition & 1 deletion src/vs/workbench/contrib/debug/browser/variablesView.ts
Original file line number Diff line number Diff line change
Expand Up @@ -317,7 +317,7 @@ class ScopesRenderer implements ITreeRenderer<IScope, FuzzyScore, IScopeTemplate

renderTemplate(container: HTMLElement): IScopeTemplateData {
const name = dom.append(container, $('.scope'));
const label = new HighlightedLabel(name, false);
const label = new HighlightedLabel(name);

return { name, label };
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,7 @@ suite('Debug - Base Debug View', () => {
let expression = $('.');
let name = $('.');
let value = $('.');
let label = new HighlightedLabel(name, false);
let label = new HighlightedLabel(name);
renderVariable(variable, { expression, name, value, label }, false, []);

assert.strictEqual(label.element.textContent, 'foo');
Expand Down
12 changes: 6 additions & 6 deletions src/vs/workbench/contrib/markers/browser/markersTreeViewer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -361,7 +361,7 @@ class MarkerWidget extends Disposable {
for (let index = 0; index < (multiline ? lines.length : 1); index++) {
lastLineElement = dom.append(this.messageAndDetailsContainer, dom.$('.marker-message-line'));
const messageElement = dom.append(lastLineElement, dom.$('.marker-message'));
const highlightedLabel = new HighlightedLabel(messageElement, false);
const highlightedLabel = new HighlightedLabel(messageElement);
highlightedLabel.set(lines[index].length > 1000 ? `${lines[index].substring(0, 1000)}...` : lines[index], lineMatches[index]);
if (lines[index] === '') {
lastLineElement.style.height = `${VirtualDelegate.LINE_HEIGHT}px`;
Expand All @@ -374,19 +374,19 @@ class MarkerWidget extends Disposable {
parent.classList.add('details-container');

if (marker.source || marker.code) {
const source = new HighlightedLabel(dom.append(parent, dom.$('.marker-source')), false);
const source = new HighlightedLabel(dom.append(parent, dom.$('.marker-source')));
const sourceMatches = filterData && filterData.sourceMatches || [];
source.set(marker.source, sourceMatches);

if (marker.code) {
if (typeof marker.code === 'string') {
const code = new HighlightedLabel(dom.append(parent, dom.$('.marker-code')), false);
const code = new HighlightedLabel(dom.append(parent, dom.$('.marker-code')));
const codeMatches = filterData && filterData.codeMatches || [];
code.set(marker.code, codeMatches);
} else {
// TODO@sandeep: these widgets should be disposed
const container = dom.$('.marker-code');
const code = new HighlightedLabel(container, false);
const code = new HighlightedLabel(container);
new Link(parent, { href: marker.code.target.toString(), label: container, title: marker.code.target.toString() }, undefined, this._openerService);
const codeMatches = filterData && filterData.codeMatches || [];
code.set(marker.code.value, codeMatches);
Expand Down Expand Up @@ -414,14 +414,14 @@ export class RelatedInformationRenderer implements ITreeRenderer<RelatedInformat
dom.append(container, dom.$('.actions'));
dom.append(container, dom.$('.icon'));

data.resourceLabel = new HighlightedLabel(dom.append(container, dom.$('.related-info-resource')), false);
data.resourceLabel = new HighlightedLabel(dom.append(container, dom.$('.related-info-resource')));
data.lnCol = dom.append(container, dom.$('span.marker-line'));

const separator = dom.append(container, dom.$('span.related-info-resource-separator'));
separator.textContent = ':';
separator.style.paddingRight = '4px';

data.description = new HighlightedLabel(dom.append(container, dom.$('.marker-description')), false);
data.description = new HighlightedLabel(dom.append(container, dom.$('.marker-description')));
return data;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -910,11 +910,11 @@ class CommandColumnRenderer implements ITableRenderer<IKeybindingItemEntry, ICom
renderTemplate(container: HTMLElement): ICommandColumnTemplateData {
const commandColumn = DOM.append(container, $('.command'));
const commandLabelContainer = DOM.append(commandColumn, $('.command-label'));
const commandLabel = new HighlightedLabel(commandLabelContainer, false);
const commandLabel = new HighlightedLabel(commandLabelContainer);
const commandDefaultLabelContainer = DOM.append(commandColumn, $('.command-default-label'));
const commandDefaultLabel = new HighlightedLabel(commandDefaultLabelContainer, false);
const commandDefaultLabel = new HighlightedLabel(commandDefaultLabelContainer);
const commandIdLabelContainer = DOM.append(commandColumn, $('.command-id.code'));
const commandIdLabel = new HighlightedLabel(commandIdLabelContainer, false);
const commandIdLabel = new HighlightedLabel(commandIdLabelContainer);
return { commandColumn, commandLabelContainer, commandLabel, commandDefaultLabelContainer, commandDefaultLabel, commandIdLabelContainer, commandIdLabel };
}

Expand Down Expand Up @@ -999,7 +999,7 @@ class SourceColumnRenderer implements ITableRenderer<IKeybindingItemEntry, ISour

renderTemplate(container: HTMLElement): ISourceColumnTemplateData {
const sourceColumn = DOM.append(container, $('.source'));
const highlightedLabel = new HighlightedLabel(sourceColumn, false);
const highlightedLabel = new HighlightedLabel(sourceColumn);
return { highlightedLabel };
}

Expand Down Expand Up @@ -1038,7 +1038,7 @@ class WhenColumnRenderer implements ITableRenderer<IKeybindingItemEntry, IWhenCo
const element = DOM.append(container, $('.when'));

const whenContainer = DOM.append(element, $('div.when-label'));
const whenLabel = new HighlightedLabel(whenContainer, false);
const whenLabel = new HighlightedLabel(whenContainer);
const whenInput = new InputBox(element, this.contextViewService, {
validationOptions: {
validation: (value) => {
Expand Down

0 comments on commit cf35554

Please sign in to comment.