mirror of
https://github.com/ckaczor/azuredatastudio.git
synced 2026-02-10 18:22:34 -05:00
Merge from vscode 7eaf220cafb9d9e901370ffce02229171cbf3ea6
This commit is contained in:
committed by
Anthony Dresser
parent
39d9eed585
commit
a63578e6f7
@@ -10,7 +10,6 @@ import { CharCode } from 'vs/base/common/charCode';
|
||||
import { Color } from 'vs/base/common/color';
|
||||
import { KeyCode } from 'vs/base/common/keyCodes';
|
||||
import { Disposable } from 'vs/base/common/lifecycle';
|
||||
import { escape } from 'vs/base/common/strings';
|
||||
import { ContentWidgetPositionPreference, IActiveCodeEditor, ICodeEditor, IContentWidget, IContentWidgetPosition } from 'vs/editor/browser/editorBrowser';
|
||||
import { EditorAction, ServicesAccessor, registerEditorAction, registerEditorContribution } from 'vs/editor/browser/editorExtensions';
|
||||
import { Position } from 'vs/editor/common/core/position';
|
||||
@@ -31,6 +30,8 @@ import { SemanticTokenRule, TokenStyleData, TokenStyle } from 'vs/platform/theme
|
||||
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
|
||||
import { SEMANTIC_HIGHLIGHTING_SETTING_ID, IEditorSemanticHighlightingOptions } from 'vs/editor/common/services/modelServiceImpl';
|
||||
|
||||
const $ = dom.$;
|
||||
|
||||
class InspectEditorTokensController extends Disposable implements IEditorContribution {
|
||||
|
||||
public static readonly ID = 'editor.contrib.inspectEditorTokens';
|
||||
@@ -151,23 +152,11 @@ function renderTokenText(tokenText: string): string {
|
||||
let charCode = tokenText.charCodeAt(charIndex);
|
||||
switch (charCode) {
|
||||
case CharCode.Tab:
|
||||
result += '→';
|
||||
result += '\u2192'; // →
|
||||
break;
|
||||
|
||||
case CharCode.Space:
|
||||
result += '·';
|
||||
break;
|
||||
|
||||
case CharCode.LessThan:
|
||||
result += '<';
|
||||
break;
|
||||
|
||||
case CharCode.GreaterThan:
|
||||
result += '>';
|
||||
break;
|
||||
|
||||
case CharCode.Ampersand:
|
||||
result += '&';
|
||||
result += '\u00B7'; // ·
|
||||
break;
|
||||
|
||||
default:
|
||||
@@ -246,8 +235,7 @@ class InspectEditorTokensWidget extends Disposable implements IContentWidget {
|
||||
if (this._isDisposed) {
|
||||
return;
|
||||
}
|
||||
let text = this._compute(grammar, semanticTokens, position);
|
||||
this._domNode.innerHTML = text;
|
||||
this._compute(grammar, semanticTokens, position);
|
||||
this._domNode.style.maxWidth = `${Math.max(this._editor.getLayoutInfo().width * 0.66, 500)}px`;
|
||||
this._editor.layoutContentWidget(this);
|
||||
}, (err) => {
|
||||
@@ -268,11 +256,12 @@ class InspectEditorTokensWidget extends Disposable implements IContentWidget {
|
||||
return this._themeService.getColorTheme().semanticHighlighting;
|
||||
}
|
||||
|
||||
private _compute(grammar: IGrammar | null, semanticTokens: SemanticTokensResult | null, position: Position): string {
|
||||
private _compute(grammar: IGrammar | null, semanticTokens: SemanticTokensResult | null, position: Position) {
|
||||
const textMateTokenInfo = grammar && this._getTokensAtPosition(grammar, position);
|
||||
const semanticTokenInfo = semanticTokens && this._getSemanticTokenAtPosition(semanticTokens, position);
|
||||
if (!textMateTokenInfo && !semanticTokenInfo) {
|
||||
return 'No grammar or semantic tokens available.';
|
||||
dom.reset(this._domNode, 'No grammar or semantic tokens available.');
|
||||
return;
|
||||
}
|
||||
|
||||
let tmMetadata = textMateTokenInfo?.metadata;
|
||||
@@ -283,91 +272,125 @@ class InspectEditorTokensWidget extends Disposable implements IContentWidget {
|
||||
|
||||
const tokenText = semTokenText || tmTokenText || '';
|
||||
|
||||
let result = '';
|
||||
result += `<h2 class="tiw-token">${tokenText}<span class="tiw-token-length">(${tokenText.length} ${tokenText.length === 1 ? 'char' : 'chars'})</span></h2>`;
|
||||
result += `<hr class="tiw-metadata-separator" style="clear:both"/>`;
|
||||
|
||||
result += `<table class="tiw-metadata-table"><tbody>`;
|
||||
result += `<tr><td class="tiw-metadata-key">language</td><td class="tiw-metadata-value">${escape(tmMetadata?.languageIdentifier.language || '')}</td></tr>`;
|
||||
result += `<tr><td class="tiw-metadata-key">standard token type</td><td class="tiw-metadata-value">${this._tokenTypeToString(tmMetadata?.tokenType || StandardTokenType.Other)}</td></tr>`;
|
||||
|
||||
result += this._formatMetadata(semMetadata, tmMetadata);
|
||||
result += `</tbody></table>`;
|
||||
dom.reset(this._domNode,
|
||||
$('h2.tiw-token', undefined,
|
||||
tokenText,
|
||||
$('span.tiw-token-length', undefined, `${tokenText.length} ${tokenText.length === 1 ? 'char' : 'chars'}`)));
|
||||
dom.append(this._domNode, $('hr.tiw-metadata-separator', { 'style': 'clear:both' }));
|
||||
dom.append(this._domNode, $('table.tiw-metadata-table', undefined,
|
||||
$('tbody', undefined,
|
||||
$('tr', undefined,
|
||||
$('td.tiw-metadata-key', undefined, 'language'),
|
||||
$('td.tiw-metadata-value', undefined, tmMetadata?.languageIdentifier.language || '')
|
||||
),
|
||||
$('tr', undefined,
|
||||
$('td.tiw-metadata-key', undefined, 'standard token type' as string),
|
||||
$('td.tiw-metadata-value', undefined, this._tokenTypeToString(tmMetadata?.tokenType || StandardTokenType.Other))
|
||||
),
|
||||
...this._formatMetadata(semMetadata, tmMetadata)
|
||||
)
|
||||
));
|
||||
|
||||
if (semanticTokenInfo) {
|
||||
result += `<hr class="tiw-metadata-separator"/>`;
|
||||
result += `<table class="tiw-metadata-table"><tbody>`;
|
||||
result += `<tr><td class="tiw-metadata-key">semantic token type</td><td class="tiw-metadata-value">${semanticTokenInfo.type}</td></tr>`;
|
||||
dom.append(this._domNode, $('hr.tiw-metadata-separator'));
|
||||
const table = dom.append(this._domNode, $('table.tiw-metadata-table', undefined));
|
||||
const tbody = dom.append(table, $('tbody', undefined,
|
||||
$('tr', undefined,
|
||||
$('td.tiw-metadata-key', undefined, 'semantic token type' as string),
|
||||
$('td.tiw-metadata-value', undefined, semanticTokenInfo.type)
|
||||
)
|
||||
));
|
||||
if (semanticTokenInfo.modifiers.length) {
|
||||
result += `<tr><td class="tiw-metadata-key">modifiers</td><td class="tiw-metadata-value">${semanticTokenInfo.modifiers.join(' ')}</td></tr>`;
|
||||
dom.append(tbody, $('tr', undefined,
|
||||
$('td.tiw-metadata-key', undefined, 'modifiers'),
|
||||
$('td.tiw-metadata-value', undefined, semanticTokenInfo.modifiers.join(' ')),
|
||||
));
|
||||
}
|
||||
if (semanticTokenInfo.metadata) {
|
||||
const properties: (keyof TokenStyleData)[] = ['foreground', 'bold', 'italic', 'underline'];
|
||||
const propertiesByDefValue: { [rule: string]: string[] } = {};
|
||||
const allDefValues = []; // remember the order
|
||||
const allDefValues = new Array<[Array<HTMLElement | string>, string]>(); // remember the order
|
||||
// first collect to detect when the same rule is used for multiple properties
|
||||
for (let property of properties) {
|
||||
if (semanticTokenInfo.metadata[property] !== undefined) {
|
||||
const definition = semanticTokenInfo.definitions[property];
|
||||
const defValue = this._renderTokenStyleDefinition(definition, property);
|
||||
let properties = propertiesByDefValue[defValue];
|
||||
const defValueStr = defValue.map(el => el instanceof HTMLElement ? el.outerHTML : el).join();
|
||||
let properties = propertiesByDefValue[defValueStr];
|
||||
if (!properties) {
|
||||
propertiesByDefValue[defValue] = properties = [];
|
||||
allDefValues.push(defValue);
|
||||
propertiesByDefValue[defValueStr] = properties = [];
|
||||
allDefValues.push([defValue, defValueStr]);
|
||||
}
|
||||
properties.push(property);
|
||||
}
|
||||
}
|
||||
for (let defValue of allDefValues) {
|
||||
result += `<tr><td class="tiw-metadata-key">${propertiesByDefValue[defValue].join(', ')}</td><td class="tiw-metadata-value">${defValue}</td></tr>`;
|
||||
for (const [defValue, defValueStr] of allDefValues) {
|
||||
dom.append(tbody, $('tr', undefined,
|
||||
$('td.tiw-metadata-key', undefined, propertiesByDefValue[defValueStr].join(', ')),
|
||||
$('td.tiw-metadata-value', undefined, ...defValue)
|
||||
));
|
||||
}
|
||||
}
|
||||
result += `</tbody></table>`;
|
||||
}
|
||||
|
||||
if (textMateTokenInfo) {
|
||||
let theme = this._themeService.getColorTheme();
|
||||
result += `<hr class="tiw-metadata-separator"/>`;
|
||||
result += `<table class="tiw-metadata-table"><tbody>`;
|
||||
dom.append(this._domNode, $('hr.tiw-metadata-separator'));
|
||||
const table = dom.append(this._domNode, $('table.tiw-metadata-table'));
|
||||
const tbody = dom.append(table, $('tbody'));
|
||||
|
||||
if (tmTokenText && tmTokenText !== tokenText) {
|
||||
result += `<tr><td class="tiw-metadata-key">textmate token</td><td class="tiw-metadata-value">${tmTokenText} (${tmTokenText.length})</td></tr>`;
|
||||
dom.append(tbody, $('tr', undefined,
|
||||
$('td.tiw-metadata-key', undefined, 'textmate token' as string),
|
||||
$('td.tiw-metadata-value', undefined, `${tmTokenText} (${tmTokenText.length})`)
|
||||
));
|
||||
}
|
||||
let scopes = '';
|
||||
const scopes = new Array<HTMLElement | string>();
|
||||
for (let i = textMateTokenInfo.token.scopes.length - 1; i >= 0; i--) {
|
||||
scopes += escape(textMateTokenInfo.token.scopes[i]);
|
||||
scopes.push(textMateTokenInfo.token.scopes[i]);
|
||||
if (i > 0) {
|
||||
scopes += '<br>';
|
||||
scopes.push($('br'));
|
||||
}
|
||||
}
|
||||
result += `<tr><td class="tiw-metadata-key">textmate scopes</td><td class="tiw-metadata-value tiw-metadata-scopes">${scopes}</td></tr>`;
|
||||
dom.append(tbody, $('tr', undefined,
|
||||
$('td.tiw-metadata-key', undefined, 'textmate scopes' as string),
|
||||
$('td.tiw-metadata-value.tiw-metadata-scopes', undefined, ...scopes),
|
||||
));
|
||||
|
||||
let matchingRule = findMatchingThemeRule(theme, textMateTokenInfo.token.scopes, false);
|
||||
const semForeground = semanticTokenInfo?.metadata?.foreground;
|
||||
if (matchingRule) {
|
||||
let defValue = `<code class="tiw-theme-selector">${matchingRule.rawSelector}\n${JSON.stringify(matchingRule.settings, null, '\t')}</code>`;
|
||||
if (semForeground !== textMateTokenInfo.metadata.foreground) {
|
||||
let defValue = $('code.tiw-theme-selector', undefined,
|
||||
matchingRule.rawSelector, $('br'), JSON.stringify(matchingRule.settings, null, '\t'));
|
||||
if (semForeground) {
|
||||
defValue = `<s>${defValue}</s>`;
|
||||
defValue = $('s', undefined, defValue);
|
||||
}
|
||||
result += `<tr><td class="tiw-metadata-key">foreground</td><td class="tiw-metadata-value">${defValue}</td></tr>`;
|
||||
dom.append(tbody, $('tr', undefined,
|
||||
$('td.tiw-metadata-key', undefined, 'foreground'),
|
||||
$('td.tiw-metadata-value', undefined, defValue),
|
||||
));
|
||||
}
|
||||
} else if (!semForeground) {
|
||||
result += `<tr><td class="tiw-metadata-key">foreground</td><td class="tiw-metadata-value">No theme selector</td></tr>`;
|
||||
dom.append(tbody, $('tr', undefined,
|
||||
$('td.tiw-metadata-key', undefined, 'foreground'),
|
||||
$('td.tiw-metadata-value', undefined, 'No theme selector' as string),
|
||||
));
|
||||
}
|
||||
result += `</tbody></table>`;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private _formatMetadata(semantic?: IDecodedMetadata, tm?: IDecodedMetadata) {
|
||||
let result = '';
|
||||
private _formatMetadata(semantic?: IDecodedMetadata, tm?: IDecodedMetadata): Array<HTMLElement | string> {
|
||||
const elements = new Array<HTMLElement | string>();
|
||||
|
||||
function render(property: 'foreground' | 'background') {
|
||||
let value = semantic?.[property] || tm?.[property];
|
||||
if (value !== undefined) {
|
||||
const semanticStyle = semantic?.[property] ? 'tiw-metadata-semantic' : '';
|
||||
result += `<tr><td class="tiw-metadata-key">${property}</td><td class="tiw-metadata-value ${semanticStyle}">${value}</td></tr>`;
|
||||
|
||||
elements.push($('tr', undefined,
|
||||
$('td.tiw-metadata-key', undefined, property),
|
||||
$(`td.tiw-metadata-value.${semanticStyle}`, undefined, value)
|
||||
));
|
||||
}
|
||||
return value;
|
||||
}
|
||||
@@ -377,17 +400,23 @@ class InspectEditorTokensWidget extends Disposable implements IContentWidget {
|
||||
if (foreground && background) {
|
||||
const backgroundColor = Color.fromHex(background), foregroundColor = Color.fromHex(foreground);
|
||||
if (backgroundColor.isOpaque()) {
|
||||
result += `<tr><td class="tiw-metadata-key">contrast ratio</td><td class="tiw-metadata-value">${backgroundColor.getContrastRatio(foregroundColor.makeOpaque(backgroundColor)).toFixed(2)}</td></tr>`;
|
||||
elements.push($('tr', undefined,
|
||||
$('td.tiw-metadata-key', undefined, 'contrast ratio' as string),
|
||||
$('td.tiw-metadata-value', undefined, backgroundColor.getContrastRatio(foregroundColor.makeOpaque(backgroundColor)).toFixed(2))
|
||||
));
|
||||
} else {
|
||||
result += '<tr><td class="tiw-metadata-key">Contrast ratio cannot be precise for background colors that use transparency</td><td class="tiw-metadata-value"></td></tr>';
|
||||
elements.push($('tr', undefined,
|
||||
$('td.tiw-metadata-key', undefined, 'Contrast ratio cannot be precise for background colors that use transparency' as string),
|
||||
$('td.tiw-metadata-value')
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
let fontStyleLabels: string[] = [];
|
||||
const fontStyleLabels = new Array<HTMLElement | string>();
|
||||
|
||||
function addStyle(key: 'bold' | 'italic' | 'underline') {
|
||||
if (semantic && semantic[key]) {
|
||||
fontStyleLabels.push(`<span class='tiw-metadata-semantic'>${key}</span>`);
|
||||
fontStyleLabels.push($('span.tiw-metadata-semantic', undefined, key));
|
||||
} else if (tm && tm[key]) {
|
||||
fontStyleLabels.push(key);
|
||||
}
|
||||
@@ -396,9 +425,12 @@ class InspectEditorTokensWidget extends Disposable implements IContentWidget {
|
||||
addStyle('italic');
|
||||
addStyle('underline');
|
||||
if (fontStyleLabels.length) {
|
||||
result += `<tr><td class="tiw-metadata-key">font style</td><td class="tiw-metadata-value">${fontStyleLabels.join(' ')}</td></tr>`;
|
||||
elements.push($('tr', undefined,
|
||||
$('td.tiw-metadata-key', undefined, 'font style' as string),
|
||||
$('td.tiw-metadata-value', undefined, fontStyleLabels.join(' '))
|
||||
));
|
||||
}
|
||||
return result;
|
||||
return elements;
|
||||
}
|
||||
|
||||
private _decodeMetadata(metadata: number): IDecodedMetadata {
|
||||
@@ -549,9 +581,10 @@ class InspectEditorTokensWidget extends Disposable implements IContentWidget {
|
||||
return null;
|
||||
}
|
||||
|
||||
private _renderTokenStyleDefinition(definition: TokenStyleDefinition | undefined, property: keyof TokenStyleData): string {
|
||||
private _renderTokenStyleDefinition(definition: TokenStyleDefinition | undefined, property: keyof TokenStyleData): Array<HTMLElement | string> {
|
||||
const elements = new Array<HTMLElement | string>();
|
||||
if (definition === undefined) {
|
||||
return '';
|
||||
return elements;
|
||||
}
|
||||
const theme = this._themeService.getColorTheme() as ColorThemeData;
|
||||
|
||||
@@ -561,20 +594,27 @@ class InspectEditorTokensWidget extends Disposable implements IContentWidget {
|
||||
const matchingRule = scopesDefinition[property];
|
||||
if (matchingRule && scopesDefinition.scope) {
|
||||
const strScopes = Array.isArray(matchingRule.scope) ? matchingRule.scope.join(', ') : String(matchingRule.scope);
|
||||
return `${escape(scopesDefinition.scope.join(' '))}<br><code class="tiw-theme-selector">${strScopes}\n${JSON.stringify(matchingRule.settings, null, '\t')}</code>`;
|
||||
elements.push(
|
||||
scopesDefinition.scope.join(' '),
|
||||
$('br'),
|
||||
$('code.tiw-theme-selector', undefined, strScopes, $('br'), JSON.stringify(matchingRule.settings, null, '\t')));
|
||||
return elements;
|
||||
}
|
||||
return '';
|
||||
return elements;
|
||||
} else if (SemanticTokenRule.is(definition)) {
|
||||
const scope = theme.getTokenStylingRuleScope(definition);
|
||||
if (scope === 'setting') {
|
||||
return `User settings: ${definition.selector.id} - ${this._renderStyleProperty(definition.style, property)}`;
|
||||
elements.push(`User settings: ${definition.selector.id} - ${this._renderStyleProperty(definition.style, property)}`);
|
||||
return elements;
|
||||
} else if (scope === 'theme') {
|
||||
return `Color theme: ${definition.selector.id} - ${this._renderStyleProperty(definition.style, property)}`;
|
||||
elements.push(`Color theme: ${definition.selector.id} - ${this._renderStyleProperty(definition.style, property)}`);
|
||||
return elements;
|
||||
}
|
||||
return '';
|
||||
return elements;
|
||||
} else {
|
||||
const style = theme.resolveTokenStyleValue(definition);
|
||||
return `Default: ${style ? this._renderStyleProperty(style, property) : ''}`;
|
||||
elements.push(`Default: ${style ? this._renderStyleProperty(style, property) : ''}`);
|
||||
return elements;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user