Shows a banner if a file has too many highlighted unicode characters.
This commit is contained in:
parent
bab15fcbb0
commit
42ec6e7924
|
@ -314,6 +314,7 @@ export class Configuration extends CommonEditorConfiguration {
|
||||||
}
|
}
|
||||||
|
|
||||||
private readonly _elementSizeObserver: ElementSizeObserver;
|
private readonly _elementSizeObserver: ElementSizeObserver;
|
||||||
|
private _reservedHeight: number = 0;
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
isSimpleWidget: boolean,
|
isSimpleWidget: boolean,
|
||||||
|
@ -365,7 +366,7 @@ export class Configuration extends CommonEditorConfiguration {
|
||||||
return {
|
return {
|
||||||
extraEditorClassName: Configuration._getExtraEditorClassName(),
|
extraEditorClassName: Configuration._getExtraEditorClassName(),
|
||||||
outerWidth: this._elementSizeObserver.getWidth(),
|
outerWidth: this._elementSizeObserver.getWidth(),
|
||||||
outerHeight: this._elementSizeObserver.getHeight(),
|
outerHeight: this._elementSizeObserver.getHeight() - this._reservedHeight,
|
||||||
emptySelectionClipboard: browser.isWebKit || browser.isFirefox,
|
emptySelectionClipboard: browser.isWebKit || browser.isFirefox,
|
||||||
pixelRatio: browser.getPixelRatio(),
|
pixelRatio: browser.getPixelRatio(),
|
||||||
zoomLevel: browser.getZoomLevel(),
|
zoomLevel: browser.getZoomLevel(),
|
||||||
|
@ -380,4 +381,9 @@ export class Configuration extends CommonEditorConfiguration {
|
||||||
protected readConfiguration(bareFontInfo: BareFontInfo): FontInfo {
|
protected readConfiguration(bareFontInfo: BareFontInfo): FontInfo {
|
||||||
return CSSBasedConfiguration.INSTANCE.readConfiguration(bareFontInfo);
|
return CSSBasedConfiguration.INSTANCE.readConfiguration(bareFontInfo);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public reserveHeight(height: number) {
|
||||||
|
this._reservedHeight = height;
|
||||||
|
this._recomputeOptions();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -899,6 +899,8 @@ export interface ICodeEditor extends editorCommon.IEditor {
|
||||||
* @internal
|
* @internal
|
||||||
*/
|
*/
|
||||||
hasModel(): this is IActiveCodeEditor;
|
hasModel(): this is IActiveCodeEditor;
|
||||||
|
|
||||||
|
setBanner(bannerDomNode: HTMLElement | null, height: number): void;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -244,6 +244,8 @@ export class CodeEditorWidget extends Disposable implements editorBrowser.ICodeE
|
||||||
private _decorationTypeKeysToIds: { [decorationTypeKey: string]: string[] };
|
private _decorationTypeKeysToIds: { [decorationTypeKey: string]: string[] };
|
||||||
private _decorationTypeSubtypes: { [decorationTypeKey: string]: { [subtype: string]: boolean } };
|
private _decorationTypeSubtypes: { [decorationTypeKey: string]: { [subtype: string]: boolean } };
|
||||||
|
|
||||||
|
private _bannerDomNode: HTMLElement | null = null;
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
domElement: HTMLElement,
|
domElement: HTMLElement,
|
||||||
_options: Readonly<editorBrowser.IEditorConstructionOptions>,
|
_options: Readonly<editorBrowser.IEditorConstructionOptions>,
|
||||||
|
@ -1490,6 +1492,19 @@ export class CodeEditorWidget extends Disposable implements editorBrowser.ICodeE
|
||||||
Configuration.applyFontInfoSlow(target, this._configuration.options.get(EditorOption.fontInfo));
|
Configuration.applyFontInfoSlow(target, this._configuration.options.get(EditorOption.fontInfo));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public setBanner(domNode: HTMLElement | null, height: number): void {
|
||||||
|
if (this._bannerDomNode && this._domElement.contains(this._bannerDomNode)) {
|
||||||
|
this._domElement.removeChild(this._bannerDomNode);
|
||||||
|
}
|
||||||
|
|
||||||
|
this._bannerDomNode = domNode;
|
||||||
|
this._configuration.reserveHeight(height);
|
||||||
|
|
||||||
|
if (this._bannerDomNode) {
|
||||||
|
this._domElement.prepend(this._bannerDomNode);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
protected _attachModel(model: ITextModel | null): void {
|
protected _attachModel(model: ITextModel | null): void {
|
||||||
if (!model) {
|
if (!model) {
|
||||||
this._modelData = null;
|
this._modelData = null;
|
||||||
|
@ -1703,6 +1718,9 @@ export class CodeEditorWidget extends Disposable implements editorBrowser.ICodeE
|
||||||
if (removeDomNode && this._domElement.contains(removeDomNode)) {
|
if (removeDomNode && this._domElement.contains(removeDomNode)) {
|
||||||
this._domElement.removeChild(removeDomNode);
|
this._domElement.removeChild(removeDomNode);
|
||||||
}
|
}
|
||||||
|
if (this._bannerDomNode && this._domElement.contains(this._bannerDomNode)) {
|
||||||
|
this._domElement.removeChild(this._bannerDomNode);
|
||||||
|
}
|
||||||
|
|
||||||
return model;
|
return model;
|
||||||
}
|
}
|
||||||
|
|
|
@ -458,6 +458,7 @@ export abstract class CommonEditorConfiguration extends Disposable implements IC
|
||||||
|
|
||||||
protected abstract readConfiguration(styling: BareFontInfo): FontInfo;
|
protected abstract readConfiguration(styling: BareFontInfo): FontInfo;
|
||||||
|
|
||||||
|
public abstract reserveHeight(height: number): void;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const editorConfigurationBaseNode = Object.freeze<IConfigurationNode>({
|
export const editorConfigurationBaseNode = Object.freeze<IConfigurationNode>({
|
||||||
|
|
|
@ -162,6 +162,7 @@ export interface IConfiguration extends IDisposable {
|
||||||
observeReferenceElement(dimension?: IDimension): void;
|
observeReferenceElement(dimension?: IDimension): void;
|
||||||
updatePixelRatio(): void;
|
updatePixelRatio(): void;
|
||||||
setIsDominatedByLongLines(isDominatedByLongLines: boolean): void;
|
setIsDominatedByLongLines(isDominatedByLongLines: boolean): void;
|
||||||
|
reserveHeight(height: number): void;
|
||||||
}
|
}
|
||||||
|
|
||||||
// --- view
|
// --- view
|
||||||
|
|
|
@ -6,9 +6,11 @@
|
||||||
import { IRange, Range } from 'vs/editor/common/core/range';
|
import { IRange, Range } from 'vs/editor/common/core/range';
|
||||||
import { Searcher } from 'vs/editor/common/model/textModelSearch';
|
import { Searcher } from 'vs/editor/common/model/textModelSearch';
|
||||||
import * as strings from 'vs/base/common/strings';
|
import * as strings from 'vs/base/common/strings';
|
||||||
|
import { IUnicodeHighlightsResult } from 'vs/editor/common/services/editorWorkerService';
|
||||||
|
import { assertNever } from 'vs/base/common/types';
|
||||||
|
|
||||||
export class UnicodeTextModelHighlighter {
|
export class UnicodeTextModelHighlighter {
|
||||||
public static computeUnicodeHighlights(model: IUnicodeCharacterSearcherTarget, options: UnicodeHighlighterOptions, range?: IRange): Range[] {
|
public static computeUnicodeHighlights(model: IUnicodeCharacterSearcherTarget, options: UnicodeHighlighterOptions, range?: IRange): IUnicodeHighlightsResult {
|
||||||
const startLine = range ? range.startLineNumber : 1;
|
const startLine = range ? range.startLineNumber : 1;
|
||||||
const endLine = range ? range.endLineNumber : model.getLineCount();
|
const endLine = range ? range.endLineNumber : model.getLineCount();
|
||||||
|
|
||||||
|
@ -23,8 +25,15 @@ export class UnicodeTextModelHighlighter {
|
||||||
}
|
}
|
||||||
|
|
||||||
const searcher = new Searcher(null, regex);
|
const searcher = new Searcher(null, regex);
|
||||||
const result: Range[] = [];
|
const ranges: Range[] = [];
|
||||||
|
let hasMore = false;
|
||||||
let m: RegExpExecArray | null;
|
let m: RegExpExecArray | null;
|
||||||
|
|
||||||
|
let ambiguousCharacterCount = 0;
|
||||||
|
let invisibleCharacterCount = 0;
|
||||||
|
let nonBasicAsciiCharacterCount = 0;
|
||||||
|
|
||||||
|
forLoop:
|
||||||
for (let lineNumber = startLine, lineCount = endLine; lineNumber <= lineCount; lineNumber++) {
|
for (let lineNumber = startLine, lineCount = endLine; lineNumber <= lineCount; lineNumber++) {
|
||||||
const lineContent = model.getLineContent(lineNumber);
|
const lineContent = model.getLineContent(lineNumber);
|
||||||
const lineLength = lineContent.length;
|
const lineLength = lineContent.length;
|
||||||
|
@ -51,19 +60,37 @@ export class UnicodeTextModelHighlighter {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
const str = lineContent.substring(startIndex, endIndex);
|
const str = lineContent.substring(startIndex, endIndex);
|
||||||
if (codePointHighlighter.shouldHighlightNonBasicASCII(str) !== SimpleHighlightReason.None) {
|
const highlightReason = codePointHighlighter.shouldHighlightNonBasicASCII(str);
|
||||||
result.push(new Range(lineNumber, startIndex + 1, lineNumber, endIndex + 1));
|
|
||||||
|
|
||||||
const maxResultLength = 1000;
|
if (highlightReason !== SimpleHighlightReason.None) {
|
||||||
if (result.length > maxResultLength) {
|
if (highlightReason === SimpleHighlightReason.Ambiguous) {
|
||||||
// TODO@hediet a message should be shown in this case
|
ambiguousCharacterCount++;
|
||||||
break;
|
} else if (highlightReason === SimpleHighlightReason.Invisible) {
|
||||||
|
invisibleCharacterCount++;
|
||||||
|
} else if (highlightReason === SimpleHighlightReason.NonBasicASCII) {
|
||||||
|
nonBasicAsciiCharacterCount++;
|
||||||
|
} else {
|
||||||
|
assertNever(highlightReason);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const MAX_RESULT_LENGTH = 1000;
|
||||||
|
if (ranges.length >= MAX_RESULT_LENGTH) {
|
||||||
|
hasMore = true;
|
||||||
|
break forLoop;
|
||||||
|
}
|
||||||
|
|
||||||
|
ranges.push(new Range(lineNumber, startIndex + 1, lineNumber, endIndex + 1));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} while (m);
|
} while (m);
|
||||||
}
|
}
|
||||||
return result;
|
return {
|
||||||
|
ranges,
|
||||||
|
hasMore,
|
||||||
|
ambiguousCharacterCount,
|
||||||
|
invisibleCharacterCount,
|
||||||
|
nonBasicAsciiCharacterCount
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
public static computeUnicodeHighlightReason(char: string, options: UnicodeHighlighterOptions): UnicodeHighlighterReason | null {
|
public static computeUnicodeHighlightReason(char: string, options: UnicodeHighlighterOptions): UnicodeHighlighterReason | null {
|
||||||
|
|
|
@ -18,7 +18,7 @@ import { ensureValidWordDefinition, getWordAtText } from 'vs/editor/common/model
|
||||||
import { IInplaceReplaceSupportResult, ILink, TextEdit } from 'vs/editor/common/modes';
|
import { IInplaceReplaceSupportResult, ILink, TextEdit } from 'vs/editor/common/modes';
|
||||||
import { ILinkComputerTarget, computeLinks } from 'vs/editor/common/modes/linkComputer';
|
import { ILinkComputerTarget, computeLinks } from 'vs/editor/common/modes/linkComputer';
|
||||||
import { BasicInplaceReplace } from 'vs/editor/common/modes/supports/inplaceReplaceSupport';
|
import { BasicInplaceReplace } from 'vs/editor/common/modes/supports/inplaceReplaceSupport';
|
||||||
import { IDiffComputationResult } from 'vs/editor/common/services/editorWorkerService';
|
import { IDiffComputationResult, IUnicodeHighlightsResult } from 'vs/editor/common/services/editorWorkerService';
|
||||||
import { createMonacoBaseAPI } from 'vs/editor/common/standalone/standaloneBase';
|
import { createMonacoBaseAPI } from 'vs/editor/common/standalone/standaloneBase';
|
||||||
import * as types from 'vs/base/common/types';
|
import * as types from 'vs/base/common/types';
|
||||||
import { EditorWorkerHost } from 'vs/editor/common/services/editorWorkerServiceImpl';
|
import { EditorWorkerHost } from 'vs/editor/common/services/editorWorkerServiceImpl';
|
||||||
|
@ -372,10 +372,10 @@ export class EditorSimpleWorker implements IRequestHandler, IDisposable {
|
||||||
delete this._models[strURL];
|
delete this._models[strURL];
|
||||||
}
|
}
|
||||||
|
|
||||||
public async computeUnicodeHighlights(url: string, options: UnicodeHighlighterOptions, range?: IRange): Promise<IRange[]> {
|
public async computeUnicodeHighlights(url: string, options: UnicodeHighlighterOptions, range?: IRange): Promise<IUnicodeHighlightsResult> {
|
||||||
const model = this._getModel(url);
|
const model = this._getModel(url);
|
||||||
if (!model) {
|
if (!model) {
|
||||||
return [];
|
return { ranges: [], hasMore: false, ambiguousCharacterCount: 0, invisibleCharacterCount: 0, nonBasicAsciiCharacterCount: 0 };
|
||||||
}
|
}
|
||||||
return UnicodeTextModelHighlighter.computeUnicodeHighlights(model, options, range);
|
return UnicodeTextModelHighlighter.computeUnicodeHighlights(model, options, range);
|
||||||
}
|
}
|
||||||
|
|
|
@ -23,7 +23,7 @@ export interface IEditorWorkerService {
|
||||||
readonly _serviceBrand: undefined;
|
readonly _serviceBrand: undefined;
|
||||||
|
|
||||||
canComputeUnicodeHighlights(uri: URI): boolean;
|
canComputeUnicodeHighlights(uri: URI): boolean;
|
||||||
computedUnicodeHighlights(uri: URI, options: UnicodeHighlighterOptions, range?: IRange): Promise<IRange[]>;
|
computedUnicodeHighlights(uri: URI, options: UnicodeHighlighterOptions, range?: IRange): Promise<IUnicodeHighlightsResult>;
|
||||||
|
|
||||||
computeDiff(original: URI, modified: URI, ignoreTrimWhitespace: boolean, maxComputationTime: number): Promise<IDiffComputationResult | null>;
|
computeDiff(original: URI, modified: URI, ignoreTrimWhitespace: boolean, maxComputationTime: number): Promise<IDiffComputationResult | null>;
|
||||||
|
|
||||||
|
@ -38,3 +38,11 @@ export interface IEditorWorkerService {
|
||||||
canNavigateValueSet(resource: URI): boolean;
|
canNavigateValueSet(resource: URI): boolean;
|
||||||
navigateValueSet(resource: URI, range: IRange, up: boolean): Promise<IInplaceReplaceSupportResult | null>;
|
navigateValueSet(resource: URI, range: IRange, up: boolean): Promise<IInplaceReplaceSupportResult | null>;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface IUnicodeHighlightsResult {
|
||||||
|
ranges: IRange[];
|
||||||
|
hasMore: boolean;
|
||||||
|
nonBasicAsciiCharacterCount: number;
|
||||||
|
invisibleCharacterCount: number;
|
||||||
|
ambiguousCharacterCount: number;
|
||||||
|
}
|
||||||
|
|
|
@ -15,7 +15,7 @@ import { ITextModel } from 'vs/editor/common/model';
|
||||||
import * as modes from 'vs/editor/common/modes';
|
import * as modes from 'vs/editor/common/modes';
|
||||||
import { LanguageConfigurationRegistry } from 'vs/editor/common/modes/languageConfigurationRegistry';
|
import { LanguageConfigurationRegistry } from 'vs/editor/common/modes/languageConfigurationRegistry';
|
||||||
import { EditorSimpleWorker } from 'vs/editor/common/services/editorSimpleWorker';
|
import { EditorSimpleWorker } from 'vs/editor/common/services/editorSimpleWorker';
|
||||||
import { IDiffComputationResult, IEditorWorkerService } from 'vs/editor/common/services/editorWorkerService';
|
import { IDiffComputationResult, IEditorWorkerService, IUnicodeHighlightsResult } from 'vs/editor/common/services/editorWorkerService';
|
||||||
import { IModelService } from 'vs/editor/common/services/modelService';
|
import { IModelService } from 'vs/editor/common/services/modelService';
|
||||||
import { ITextResourceConfigurationService } from 'vs/editor/common/services/textResourceConfigurationService';
|
import { ITextResourceConfigurationService } from 'vs/editor/common/services/textResourceConfigurationService';
|
||||||
import { regExpFlags } from 'vs/base/common/strings';
|
import { regExpFlags } from 'vs/base/common/strings';
|
||||||
|
@ -86,7 +86,7 @@ export class EditorWorkerServiceImpl extends Disposable implements IEditorWorker
|
||||||
return canSyncModel(this._modelService, uri);
|
return canSyncModel(this._modelService, uri);
|
||||||
}
|
}
|
||||||
|
|
||||||
public computedUnicodeHighlights(uri: URI, options: UnicodeHighlighterOptions, range?: IRange): Promise<IRange[]> {
|
public computedUnicodeHighlights(uri: URI, options: UnicodeHighlighterOptions, range?: IRange): Promise<IUnicodeHighlightsResult> {
|
||||||
return this._workerManager.withWorker().then(client => client.computedUnicodeHighlights(uri, options, range));
|
return this._workerManager.withWorker().then(client => client.computedUnicodeHighlights(uri, options, range));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -475,7 +475,7 @@ export class EditorWorkerClient extends Disposable implements IEditorWorkerClien
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
public computedUnicodeHighlights(uri: URI, options: UnicodeHighlighterOptions, range?: IRange): Promise<IRange[]> {
|
public computedUnicodeHighlights(uri: URI, options: UnicodeHighlighterOptions, range?: IRange): Promise<IUnicodeHighlightsResult> {
|
||||||
return this._withSyncedResources([uri]).then(proxy => {
|
return this._withSyncedResources([uri]).then(proxy => {
|
||||||
return proxy.computeUnicodeHighlights(uri.toString(), options, range);
|
return proxy.computeUnicodeHighlights(uri.toString(), options, range);
|
||||||
});
|
});
|
||||||
|
|
|
@ -0,0 +1,85 @@
|
||||||
|
/*---------------------------------------------------------------------------------------------
|
||||||
|
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||||
|
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||||
|
*--------------------------------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
.editor-banner {
|
||||||
|
box-sizing: border-box;
|
||||||
|
cursor: default;
|
||||||
|
width: 100%;
|
||||||
|
font-size: 12px;
|
||||||
|
display: flex;
|
||||||
|
overflow: visible;
|
||||||
|
|
||||||
|
height: 26px;
|
||||||
|
|
||||||
|
background: var(--vscode-banner-background);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
.editor-banner .icon-container {
|
||||||
|
display: flex;
|
||||||
|
flex-shrink: 0;
|
||||||
|
align-items: center;
|
||||||
|
padding: 0 6px 0 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.editor-banner .icon-container.custom-icon {
|
||||||
|
background-repeat: no-repeat;
|
||||||
|
background-position: center center;
|
||||||
|
background-size: 16px;
|
||||||
|
width: 16px;
|
||||||
|
padding: 0;
|
||||||
|
margin: 0 6px 0 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.editor-banner .message-container {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
line-height: 26px;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
white-space: nowrap;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
.editor-banner .message-container p {
|
||||||
|
margin-block-start: 0;
|
||||||
|
margin-block-end: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.editor-banner .message-actions-container {
|
||||||
|
flex-grow: 1;
|
||||||
|
flex-shrink: 0;
|
||||||
|
line-height: 26px;
|
||||||
|
margin: 0 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.editor-banner .message-actions-container a.monaco-button {
|
||||||
|
width: inherit;
|
||||||
|
margin: 2px 8px;
|
||||||
|
padding: 0px 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.editor-banner .message-actions-container a {
|
||||||
|
padding: 3px;
|
||||||
|
margin-left: 12px;
|
||||||
|
text-decoration: underline;
|
||||||
|
}
|
||||||
|
|
||||||
|
.editor-banner .action-container {
|
||||||
|
padding: 0 10px 0 6px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.editor-banner {
|
||||||
|
background-color: var(--vscode-banner-background);
|
||||||
|
}
|
||||||
|
|
||||||
|
.editor-banner,
|
||||||
|
.editor-banner .action-container .codicon,
|
||||||
|
.editor-banner .message-actions-container .monaco-link {
|
||||||
|
color: var(--vscode-banner-foreground);
|
||||||
|
}
|
||||||
|
|
||||||
|
.editor-banner .icon-container .codicon {
|
||||||
|
color: var(--vscode-banner-iconForeground);
|
||||||
|
}
|
155
src/vs/editor/contrib/unicodeHighlighter/bannerController.ts
Normal file
155
src/vs/editor/contrib/unicodeHighlighter/bannerController.ts
Normal file
|
@ -0,0 +1,155 @@
|
||||||
|
/*---------------------------------------------------------------------------------------------
|
||||||
|
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||||
|
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||||
|
*--------------------------------------------------------------------------------------------*/
|
||||||
|
import 'vs/css!./bannerController';
|
||||||
|
import { $, append, clearNode } from 'vs/base/browser/dom';
|
||||||
|
import { ActionBar } from 'vs/base/browser/ui/actionbar/actionbar';
|
||||||
|
import { Action } from 'vs/base/common/actions';
|
||||||
|
import { MarkdownString } from 'vs/base/common/htmlContent';
|
||||||
|
import { Disposable } from 'vs/base/common/lifecycle';
|
||||||
|
import { MarkdownRenderer } from 'vs/editor/browser/core/markdownRenderer';
|
||||||
|
import { ICodeEditor } from 'vs/editor/browser/editorBrowser';
|
||||||
|
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
|
||||||
|
import { ILinkDescriptor, Link } from 'vs/platform/opener/browser/link';
|
||||||
|
import { widgetClose } from 'vs/platform/theme/common/iconRegistry';
|
||||||
|
import { ThemeIcon } from 'vs/platform/theme/common/themeService';
|
||||||
|
|
||||||
|
const BANNER_ELEMENT_HEIGHT = 26;
|
||||||
|
|
||||||
|
export class BannerController extends Disposable {
|
||||||
|
private readonly banner: Banner;
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
private readonly _editor: ICodeEditor,
|
||||||
|
@IInstantiationService private readonly instantiationService: IInstantiationService,
|
||||||
|
) {
|
||||||
|
super();
|
||||||
|
|
||||||
|
this.banner = this._register(this.instantiationService.createInstance(Banner));
|
||||||
|
}
|
||||||
|
|
||||||
|
public hide() {
|
||||||
|
this._editor.setBanner(null, 0);
|
||||||
|
this.banner.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
public show(item: IBannerItem) {
|
||||||
|
this.banner.show({
|
||||||
|
...item,
|
||||||
|
onClose: () => {
|
||||||
|
this.hide();
|
||||||
|
if (item.onClose) {
|
||||||
|
item.onClose();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
this._editor.setBanner(this.banner.element, BANNER_ELEMENT_HEIGHT);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO@hediet: Investigate if this can be reused by the workspace banner (bannerPart.ts).
|
||||||
|
class Banner extends Disposable {
|
||||||
|
public element: HTMLElement;
|
||||||
|
|
||||||
|
private readonly markdownRenderer: MarkdownRenderer;
|
||||||
|
|
||||||
|
private messageActionsContainer: HTMLElement | undefined;
|
||||||
|
|
||||||
|
private actionBar: ActionBar | undefined;
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
@IInstantiationService private readonly instantiationService: IInstantiationService,
|
||||||
|
) {
|
||||||
|
super();
|
||||||
|
|
||||||
|
this.markdownRenderer = this.instantiationService.createInstance(MarkdownRenderer, {});
|
||||||
|
|
||||||
|
this.element = $('div.editor-banner');
|
||||||
|
this.element.tabIndex = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
private getAriaLabel(item: IBannerItem): string | undefined {
|
||||||
|
if (item.ariaLabel) {
|
||||||
|
return item.ariaLabel;
|
||||||
|
}
|
||||||
|
if (typeof item.message === 'string') {
|
||||||
|
return item.message;
|
||||||
|
}
|
||||||
|
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
private getBannerMessage(message: MarkdownString | string): HTMLElement {
|
||||||
|
if (typeof message === 'string') {
|
||||||
|
const element = $('span');
|
||||||
|
element.innerText = message;
|
||||||
|
return element;
|
||||||
|
}
|
||||||
|
|
||||||
|
return this.markdownRenderer.render(message).element;
|
||||||
|
}
|
||||||
|
|
||||||
|
public clear() {
|
||||||
|
clearNode(this.element);
|
||||||
|
}
|
||||||
|
|
||||||
|
public show(item: IBannerItem) {
|
||||||
|
// Clear previous item
|
||||||
|
clearNode(this.element);
|
||||||
|
|
||||||
|
// Banner aria label
|
||||||
|
const ariaLabel = this.getAriaLabel(item);
|
||||||
|
if (ariaLabel) {
|
||||||
|
this.element.setAttribute('aria-label', ariaLabel);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Icon
|
||||||
|
const iconContainer = append(this.element, $('div.icon-container'));
|
||||||
|
iconContainer.setAttribute('aria-hidden', 'true');
|
||||||
|
|
||||||
|
if (item.icon) {
|
||||||
|
iconContainer.appendChild($(`div${ThemeIcon.asCSSSelector(item.icon)}`));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Message
|
||||||
|
const messageContainer = append(this.element, $('div.message-container'));
|
||||||
|
messageContainer.setAttribute('aria-hidden', 'true');
|
||||||
|
messageContainer.appendChild(this.getBannerMessage(item.message));
|
||||||
|
|
||||||
|
// Message Actions
|
||||||
|
this.messageActionsContainer = append(this.element, $('div.message-actions-container'));
|
||||||
|
if (item.actions) {
|
||||||
|
for (const action of item.actions) {
|
||||||
|
this._register(this.instantiationService.createInstance(Link, this.messageActionsContainer, { ...action, tabIndex: -1 }, {}));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Action
|
||||||
|
const actionBarContainer = append(this.element, $('div.action-container'));
|
||||||
|
this.actionBar = this._register(new ActionBar(actionBarContainer));
|
||||||
|
this.actionBar.push(this._register(
|
||||||
|
new Action(
|
||||||
|
'banner.close',
|
||||||
|
'Close Banner',
|
||||||
|
ThemeIcon.asClassName(widgetClose),
|
||||||
|
true,
|
||||||
|
() => {
|
||||||
|
if (typeof item.onClose === 'function') {
|
||||||
|
item.onClose();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
|
), { icon: true, label: false });
|
||||||
|
this.actionBar.setFocusable(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface IBannerItem {
|
||||||
|
readonly id: string;
|
||||||
|
readonly icon: ThemeIcon | undefined;
|
||||||
|
readonly message: string | MarkdownString;
|
||||||
|
readonly actions?: ILinkDescriptor[];
|
||||||
|
readonly ariaLabel?: string;
|
||||||
|
readonly onClose?: () => void;
|
||||||
|
}
|
|
@ -5,6 +5,7 @@
|
||||||
|
|
||||||
import { RunOnceScheduler } from 'vs/base/common/async';
|
import { RunOnceScheduler } from 'vs/base/common/async';
|
||||||
import { CharCode } from 'vs/base/common/charCode';
|
import { CharCode } from 'vs/base/common/charCode';
|
||||||
|
import { Codicon } from 'vs/base/common/codicons';
|
||||||
import { IMarkdownString } from 'vs/base/common/htmlContent';
|
import { IMarkdownString } from 'vs/base/common/htmlContent';
|
||||||
import { Disposable, IDisposable } from 'vs/base/common/lifecycle';
|
import { Disposable, IDisposable } from 'vs/base/common/lifecycle';
|
||||||
import { InvisibleCharacters } from 'vs/base/common/strings';
|
import { InvisibleCharacters } from 'vs/base/common/strings';
|
||||||
|
@ -17,32 +18,44 @@ import { IEditorContribution } from 'vs/editor/common/editorCommon';
|
||||||
import { IModelDecoration, IModelDeltaDecoration, ITextModel, MinimapPosition, OverviewRulerLane, TrackedRangeStickiness } from 'vs/editor/common/model';
|
import { IModelDecoration, IModelDeltaDecoration, ITextModel, MinimapPosition, OverviewRulerLane, TrackedRangeStickiness } from 'vs/editor/common/model';
|
||||||
import { ModelDecorationOptions } from 'vs/editor/common/model/textModel';
|
import { ModelDecorationOptions } from 'vs/editor/common/model/textModel';
|
||||||
import { UnicodeHighlighterOptions, UnicodeHighlighterReason, UnicodeHighlighterReasonKind, UnicodeTextModelHighlighter } from 'vs/editor/common/modes/unicodeTextModelHighlighter';
|
import { UnicodeHighlighterOptions, UnicodeHighlighterReason, UnicodeHighlighterReasonKind, UnicodeTextModelHighlighter } from 'vs/editor/common/modes/unicodeTextModelHighlighter';
|
||||||
import { IEditorWorkerService } from 'vs/editor/common/services/editorWorkerService';
|
import { IEditorWorkerService, IUnicodeHighlightsResult } from 'vs/editor/common/services/editorWorkerService';
|
||||||
import { IModeService } from 'vs/editor/common/services/modeService';
|
import { IModeService } from 'vs/editor/common/services/modeService';
|
||||||
import { HoverAnchor, HoverAnchorType, IEditorHover, IEditorHoverParticipant, IEditorHoverStatusBar, IHoverPart } from 'vs/editor/contrib/hover/hoverTypes';
|
import { HoverAnchor, HoverAnchorType, IEditorHover, IEditorHoverParticipant, IEditorHoverStatusBar, IHoverPart } from 'vs/editor/contrib/hover/hoverTypes';
|
||||||
import { MarkdownHover, renderMarkdownHovers } from 'vs/editor/contrib/hover/markdownHoverParticipant';
|
import { MarkdownHover, renderMarkdownHovers } from 'vs/editor/contrib/hover/markdownHoverParticipant';
|
||||||
|
import { BannerController } from 'vs/editor/contrib/unicodeHighlighter/bannerController';
|
||||||
import * as nls from 'vs/nls';
|
import * as nls from 'vs/nls';
|
||||||
import { ConfigurationTarget, IConfigurationService } from 'vs/platform/configuration/common/configuration';
|
import { ConfigurationTarget, IConfigurationService } from 'vs/platform/configuration/common/configuration';
|
||||||
|
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
|
||||||
import { IOpenerService } from 'vs/platform/opener/common/opener';
|
import { IOpenerService } from 'vs/platform/opener/common/opener';
|
||||||
import { IQuickInputService, IQuickPickItem } from 'vs/platform/quickinput/common/quickInput';
|
import { IQuickInputService, IQuickPickItem } from 'vs/platform/quickinput/common/quickInput';
|
||||||
import { minimapFindMatch, minimapUnicodeHighlight, overviewRulerFindMatchForeground, overviewRulerUnicodeHighlightForeground } from 'vs/platform/theme/common/colorRegistry';
|
import { minimapFindMatch, minimapUnicodeHighlight, overviewRulerFindMatchForeground, overviewRulerUnicodeHighlightForeground } from 'vs/platform/theme/common/colorRegistry';
|
||||||
|
import { registerIcon } from 'vs/platform/theme/common/iconRegistry';
|
||||||
import { themeColorFromId } from 'vs/platform/theme/common/themeService';
|
import { themeColorFromId } from 'vs/platform/theme/common/themeService';
|
||||||
import { IWorkspaceTrustManagementService } from 'vs/platform/workspace/common/workspaceTrust';
|
import { IWorkspaceTrustManagementService } from 'vs/platform/workspace/common/workspaceTrust';
|
||||||
|
|
||||||
|
export const warningIcon = registerIcon('extensions-warning-message', Codicon.warning, nls.localize('warningIcon', 'Icon shown with a warning message in the extensions editor.'));
|
||||||
|
|
||||||
export class UnicodeHighlighter extends Disposable implements IEditorContribution {
|
export class UnicodeHighlighter extends Disposable implements IEditorContribution {
|
||||||
public static readonly ID = 'editor.contrib.unicodeHighlighter';
|
public static readonly ID = 'editor.contrib.unicodeHighlighter';
|
||||||
|
|
||||||
private _highlighter: DocumentUnicodeHighlighter | ViewportUnicodeHighlighter | null = null;
|
private _highlighter: DocumentUnicodeHighlighter | ViewportUnicodeHighlighter | null = null;
|
||||||
private _options: InternalUnicodeHighlightOptions;
|
private _options: InternalUnicodeHighlightOptions;
|
||||||
|
|
||||||
|
private readonly _bannerController: BannerController;
|
||||||
|
private _bannerClosed: boolean = false;
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
private readonly _editor: ICodeEditor,
|
private readonly _editor: ICodeEditor,
|
||||||
@IEditorWorkerService private readonly _editorWorkerService: IEditorWorkerService,
|
@IEditorWorkerService private readonly _editorWorkerService: IEditorWorkerService,
|
||||||
@IWorkspaceTrustManagementService private readonly _workspaceTrustService: IWorkspaceTrustManagementService,
|
@IWorkspaceTrustManagementService private readonly _workspaceTrustService: IWorkspaceTrustManagementService,
|
||||||
|
@IInstantiationService instantiationService: IInstantiationService,
|
||||||
) {
|
) {
|
||||||
super();
|
super();
|
||||||
|
|
||||||
|
this._bannerController = this._register(instantiationService.createInstance(BannerController, _editor));
|
||||||
|
|
||||||
this._register(this._editor.onDidChangeModel(() => {
|
this._register(this._editor.onDidChangeModel(() => {
|
||||||
|
this._bannerClosed = false;
|
||||||
this._updateHighlighter();
|
this._updateHighlighter();
|
||||||
}));
|
}));
|
||||||
|
|
||||||
|
@ -70,7 +83,57 @@ export class UnicodeHighlighter extends Disposable implements IEditorContributio
|
||||||
super.dispose();
|
super.dispose();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private readonly _updateState = (state: IUnicodeHighlightsResult | null): void => {
|
||||||
|
if (state && state.hasMore) {
|
||||||
|
if (this._bannerClosed) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// This document contains many non-basic ASCII characters.
|
||||||
|
const max = Math.max(state.ambiguousCharacterCount, state.nonBasicAsciiCharacterCount, state.invisibleCharacterCount);
|
||||||
|
|
||||||
|
let data;
|
||||||
|
if (state.nonBasicAsciiCharacterCount >= max) {
|
||||||
|
data = {
|
||||||
|
message: nls.localize('unicodeHighlighting.thisDocumentHasManyNonBasicAsciiUnicodeCharacters', 'This document contains many non-basic ASCII unicode characters'),
|
||||||
|
command: new DisableHighlightingOfNonBasicAsciiCharactersAction(),
|
||||||
|
};
|
||||||
|
} else if (state.ambiguousCharacterCount >= max) {
|
||||||
|
data = {
|
||||||
|
message: nls.localize('unicodeHighlighting.thisDocumentHasManyAmbiguousUnicodeCharacters', 'This document contains many ambiguous unicode characters'),
|
||||||
|
command: new DisableHighlightingOfAmbiguousCharactersAction(),
|
||||||
|
};
|
||||||
|
} else if (state.invisibleCharacterCount >= max) {
|
||||||
|
data = {
|
||||||
|
message: nls.localize('unicodeHighlighting.thisDocumentHasManyInvisibleUnicodeCharacters', 'This document contains many invisible unicode characters'),
|
||||||
|
command: new DisableHighlightingOfInvisibleCharactersAction(),
|
||||||
|
};
|
||||||
|
} else {
|
||||||
|
throw new Error('Unreachable');
|
||||||
|
}
|
||||||
|
|
||||||
|
this._bannerController.show({
|
||||||
|
id: 'unicodeHighlightBanner',
|
||||||
|
message: data.message,
|
||||||
|
icon: warningIcon,
|
||||||
|
actions: [
|
||||||
|
{
|
||||||
|
label: data.command.shortLabel,
|
||||||
|
href: `command:${data.command.id}`
|
||||||
|
}
|
||||||
|
],
|
||||||
|
onClose: () => {
|
||||||
|
this._bannerClosed = true;
|
||||||
|
},
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
this._bannerController.hide();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
private _updateHighlighter(): void {
|
private _updateHighlighter(): void {
|
||||||
|
this._updateState(null);
|
||||||
|
|
||||||
if (this._highlighter) {
|
if (this._highlighter) {
|
||||||
this._highlighter.dispose();
|
this._highlighter.dispose();
|
||||||
this._highlighter = null;
|
this._highlighter = null;
|
||||||
|
@ -100,9 +163,9 @@ export class UnicodeHighlighter extends Disposable implements IEditorContributio
|
||||||
};
|
};
|
||||||
|
|
||||||
if (this._editorWorkerService.canComputeUnicodeHighlights(this._editor.getModel().uri)) {
|
if (this._editorWorkerService.canComputeUnicodeHighlights(this._editor.getModel().uri)) {
|
||||||
this._highlighter = new DocumentUnicodeHighlighter(this._editor, highlightOptions, this._editorWorkerService);
|
this._highlighter = new DocumentUnicodeHighlighter(this._editor, highlightOptions, this._updateState, this._editorWorkerService);
|
||||||
} else {
|
} else {
|
||||||
this._highlighter = new ViewportUnicodeHighlighter(this._editor, highlightOptions);
|
this._highlighter = new ViewportUnicodeHighlighter(this._editor, highlightOptions, this._updateState);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -156,6 +219,7 @@ class DocumentUnicodeHighlighter extends Disposable {
|
||||||
constructor(
|
constructor(
|
||||||
private readonly _editor: IActiveCodeEditor,
|
private readonly _editor: IActiveCodeEditor,
|
||||||
private readonly _options: UnicodeHighlighterOptions,
|
private readonly _options: UnicodeHighlighterOptions,
|
||||||
|
private readonly _updateState: (state: IUnicodeHighlightsResult | null) => void,
|
||||||
@IEditorWorkerService private readonly _editorWorkerService: IEditorWorkerService,
|
@IEditorWorkerService private readonly _editorWorkerService: IEditorWorkerService,
|
||||||
) {
|
) {
|
||||||
super();
|
super();
|
||||||
|
@ -182,14 +246,20 @@ class DocumentUnicodeHighlighter extends Disposable {
|
||||||
const modelVersionId = this._model.getVersionId();
|
const modelVersionId = this._model.getVersionId();
|
||||||
this._editorWorkerService
|
this._editorWorkerService
|
||||||
.computedUnicodeHighlights(this._model.uri, this._options)
|
.computedUnicodeHighlights(this._model.uri, this._options)
|
||||||
.then((ranges) => {
|
.then((info) => {
|
||||||
if (this._model.getVersionId() !== modelVersionId) {
|
if (this._model.getVersionId() !== modelVersionId) {
|
||||||
// model changed in the meantime
|
// model changed in the meantime
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
this._updateState(info);
|
||||||
|
|
||||||
const decorations: IModelDeltaDecoration[] = [];
|
const decorations: IModelDeltaDecoration[] = [];
|
||||||
for (const range of ranges) {
|
if (!info.hasMore) {
|
||||||
decorations.push({ range: range, options: this._options.includeComments ? DECORATION : DECORATION_HIDE_IN_COMMENTS });
|
// Don't show decoration if there are too many.
|
||||||
|
// In this case, a banner is shown.
|
||||||
|
for (const range of info.ranges) {
|
||||||
|
decorations.push({ range: range, options: this._options.includeComments ? DECORATION : DECORATION_HIDE_IN_COMMENTS });
|
||||||
|
}
|
||||||
}
|
}
|
||||||
this._decorationIds = new Set(this._editor.deltaDecorations(
|
this._decorationIds = new Set(this._editor.deltaDecorations(
|
||||||
Array.from(this._decorationIds),
|
Array.from(this._decorationIds),
|
||||||
|
@ -218,7 +288,8 @@ class ViewportUnicodeHighlighter extends Disposable {
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
private readonly _editor: IActiveCodeEditor,
|
private readonly _editor: IActiveCodeEditor,
|
||||||
private readonly _options: UnicodeHighlighterOptions
|
private readonly _options: UnicodeHighlighterOptions,
|
||||||
|
private readonly _updateState: (state: IUnicodeHighlightsResult | null) => void,
|
||||||
) {
|
) {
|
||||||
super();
|
super();
|
||||||
|
|
||||||
|
@ -253,12 +324,33 @@ class ViewportUnicodeHighlighter extends Disposable {
|
||||||
|
|
||||||
const ranges = this._editor.getVisibleRanges();
|
const ranges = this._editor.getVisibleRanges();
|
||||||
const decorations: IModelDeltaDecoration[] = [];
|
const decorations: IModelDeltaDecoration[] = [];
|
||||||
|
const totalResult: IUnicodeHighlightsResult = {
|
||||||
|
ranges: [],
|
||||||
|
ambiguousCharacterCount: 0,
|
||||||
|
invisibleCharacterCount: 0,
|
||||||
|
nonBasicAsciiCharacterCount: 0,
|
||||||
|
hasMore: false,
|
||||||
|
};
|
||||||
for (const range of ranges) {
|
for (const range of ranges) {
|
||||||
const ranges = UnicodeTextModelHighlighter.computeUnicodeHighlights(this._model, this._options, range);
|
const result = UnicodeTextModelHighlighter.computeUnicodeHighlights(this._model, this._options, range);
|
||||||
for (const range of ranges) {
|
for (const r of result.ranges) {
|
||||||
|
totalResult.ranges.push(r);
|
||||||
|
}
|
||||||
|
totalResult.ambiguousCharacterCount += totalResult.ambiguousCharacterCount;
|
||||||
|
totalResult.invisibleCharacterCount += totalResult.invisibleCharacterCount;
|
||||||
|
totalResult.nonBasicAsciiCharacterCount += totalResult.nonBasicAsciiCharacterCount;
|
||||||
|
totalResult.hasMore = totalResult.hasMore || result.hasMore;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!totalResult.hasMore) {
|
||||||
|
// Don't show decorations if there are too many.
|
||||||
|
// A banner will be shown instead.
|
||||||
|
for (const range of totalResult.ranges) {
|
||||||
decorations.push({ range, options: this._options.includeComments ? DECORATION : DECORATION_HIDE_IN_COMMENTS });
|
decorations.push({ range, options: this._options.includeComments ? DECORATION : DECORATION_HIDE_IN_COMMENTS });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
this._updateState(totalResult);
|
||||||
|
|
||||||
this._decorationIds = new Set(this._editor.deltaDecorations(Array.from(this._decorationIds), decorations));
|
this._decorationIds = new Set(this._editor.deltaDecorations(Array.from(this._decorationIds), decorations));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -424,6 +516,78 @@ const DECORATION = ModelDecorationOptions.register({
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
export class DisableHighlightingOfAmbiguousCharactersAction extends EditorAction {
|
||||||
|
public static ID = 'editor.action.unicodeHighlight.disableHighlightingOfAmbiguousCharacters';
|
||||||
|
public readonly shortLabel = nls.localize('unicodeHighlight.disableHighlightingOfAmbiguousCharacters.shortLabel', '');
|
||||||
|
constructor() {
|
||||||
|
super({
|
||||||
|
id: DisableHighlightingOfAmbiguousCharactersAction.ID,
|
||||||
|
label: nls.localize('action.unicodeHighlight.disableHighlightingOfAmbiguousCharacters', 'Disable Ambiguous Highlight'),
|
||||||
|
alias: 'Disable highlighting of ambiguous characters',
|
||||||
|
precondition: undefined
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public async run(accessor: ServicesAccessor | undefined, editor: ICodeEditor, args: any): Promise<void> {
|
||||||
|
let configurationService = accessor?.get(IConfigurationService);
|
||||||
|
if (configurationService) {
|
||||||
|
this.runAction(configurationService);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public async runAction(configurationService: IConfigurationService): Promise<void> {
|
||||||
|
await configurationService.updateValue(unicodeHighlightConfigKeys.ambiguousCharacters, false, ConfigurationTarget.USER);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export class DisableHighlightingOfInvisibleCharactersAction extends EditorAction {
|
||||||
|
public static ID = 'editor.action.unicodeHighlight.disableHighlightingOfInvisibleCharacters';
|
||||||
|
public readonly shortLabel = nls.localize('unicodeHighlight.disableHighlightingOfInvisibleCharacters.shortLabel', 'Disable Invisible Highlight');
|
||||||
|
constructor() {
|
||||||
|
super({
|
||||||
|
id: DisableHighlightingOfInvisibleCharactersAction.ID,
|
||||||
|
label: nls.localize('action.unicodeHighlight.disableHighlightingOfInvisibleCharacters', 'Disable highlighting of invisible characters'),
|
||||||
|
alias: 'Disable highlighting of invisible characters',
|
||||||
|
precondition: undefined
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public async run(accessor: ServicesAccessor | undefined, editor: ICodeEditor, args: any): Promise<void> {
|
||||||
|
let configurationService = accessor?.get(IConfigurationService);
|
||||||
|
if (configurationService) {
|
||||||
|
this.runAction(configurationService);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public async runAction(configurationService: IConfigurationService): Promise<void> {
|
||||||
|
await configurationService.updateValue(unicodeHighlightConfigKeys.invisibleCharacters, false, ConfigurationTarget.USER);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export class DisableHighlightingOfNonBasicAsciiCharactersAction extends EditorAction {
|
||||||
|
public static ID = 'editor.action.unicodeHighlight.disableHighlightingOfNonBasicAsciiCharacters';
|
||||||
|
public readonly shortLabel = nls.localize('unicodeHighlight.disableHighlightingOfNonBasicAsciiCharacters.shortLabel', 'Disable Non ASCII Highlight');
|
||||||
|
constructor() {
|
||||||
|
super({
|
||||||
|
id: DisableHighlightingOfNonBasicAsciiCharactersAction.ID,
|
||||||
|
label: nls.localize('action.unicodeHighlight.dhowDisableHighlightingOfNonBasicAsciiCharacters', 'Disable highlighting of non basic ASCII characters'),
|
||||||
|
alias: 'Disable highlighting of non basic ASCII characters',
|
||||||
|
precondition: undefined
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public async run(accessor: ServicesAccessor | undefined, editor: ICodeEditor, args: any): Promise<void> {
|
||||||
|
let configurationService = accessor?.get(IConfigurationService);
|
||||||
|
if (configurationService) {
|
||||||
|
this.runAction(configurationService);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public async runAction(configurationService: IConfigurationService): Promise<void> {
|
||||||
|
await configurationService.updateValue(unicodeHighlightConfigKeys.nonBasicASCII, false, ConfigurationTarget.USER);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
interface ShowExcludeOptionsArgs {
|
interface ShowExcludeOptionsArgs {
|
||||||
codePoint: number;
|
codePoint: number;
|
||||||
reason: UnicodeHighlighterReason['kind'];
|
reason: UnicodeHighlighterReason['kind'];
|
||||||
|
@ -439,6 +603,7 @@ export class ShowExcludeOptions extends EditorAction {
|
||||||
precondition: undefined
|
precondition: undefined
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
public async run(accessor: ServicesAccessor | undefined, editor: ICodeEditor, args: any): Promise<void> {
|
public async run(accessor: ServicesAccessor | undefined, editor: ICodeEditor, args: any): Promise<void> {
|
||||||
const { codePoint, reason } = args as ShowExcludeOptionsArgs;
|
const { codePoint, reason } = args as ShowExcludeOptionsArgs;
|
||||||
|
|
||||||
|
@ -470,28 +635,16 @@ export class ShowExcludeOptions extends EditorAction {
|
||||||
];
|
];
|
||||||
|
|
||||||
if (reason === UnicodeHighlighterReasonKind.Ambiguous) {
|
if (reason === UnicodeHighlighterReasonKind.Ambiguous) {
|
||||||
options.push({
|
const action = new DisableHighlightingOfAmbiguousCharactersAction();
|
||||||
label: nls.localize('unicodeHighlight.disableHighlightingOfAmbiguousCharacters', 'Disable highlighting of ambiguous characters'),
|
options.push({ label: action.label, run: async () => action.runAction(configurationService) });
|
||||||
run: async () => {
|
|
||||||
await configurationService.updateValue(unicodeHighlightConfigKeys.ambiguousCharacters, false, ConfigurationTarget.USER);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
else if (reason === UnicodeHighlighterReasonKind.Invisible) {
|
else if (reason === UnicodeHighlighterReasonKind.Invisible) {
|
||||||
options.push({
|
const action = new DisableHighlightingOfInvisibleCharactersAction();
|
||||||
label: nls.localize('unicodeHighlight.disableHighlightingOfInvisibleCharacters', 'Disable highlighting of invisible characters'),
|
options.push({ label: action.label, run: async () => action.runAction(configurationService) });
|
||||||
run: async () => {
|
|
||||||
await configurationService.updateValue(unicodeHighlightConfigKeys.invisibleCharacters, false, ConfigurationTarget.USER);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
else if (reason === UnicodeHighlighterReasonKind.NonBasicAscii) {
|
else if (reason === UnicodeHighlighterReasonKind.NonBasicAscii) {
|
||||||
options.push({
|
const action = new DisableHighlightingOfNonBasicAsciiCharactersAction();
|
||||||
label: nls.localize('unicodeHighlight.disableHighlightingOfNonBasicAsciiCharacters', 'Disable highlighting of non basic ASCII characters'),
|
options.push({ label: action.label, run: async () => action.runAction(configurationService) });
|
||||||
run: async () => {
|
|
||||||
await configurationService.updateValue(unicodeHighlightConfigKeys.nonBasicASCII, false, ConfigurationTarget.USER);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
} else {
|
} else {
|
||||||
expectNever(reason);
|
expectNever(reason);
|
||||||
}
|
}
|
||||||
|
@ -511,5 +664,8 @@ function expectNever(value: never) {
|
||||||
throw new Error(`Unexpected value: ${value}`);
|
throw new Error(`Unexpected value: ${value}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
registerEditorAction(DisableHighlightingOfAmbiguousCharactersAction);
|
||||||
|
registerEditorAction(DisableHighlightingOfInvisibleCharactersAction);
|
||||||
|
registerEditorAction(DisableHighlightingOfNonBasicAsciiCharactersAction);
|
||||||
registerEditorAction(ShowExcludeOptions);
|
registerEditorAction(ShowExcludeOptions);
|
||||||
registerEditorContribution(UnicodeHighlighter.ID, UnicodeHighlighter);
|
registerEditorContribution(UnicodeHighlighter.ID, UnicodeHighlighter);
|
||||||
|
|
|
@ -47,4 +47,8 @@ export class TestConfiguration extends CommonEditorConfiguration {
|
||||||
maxDigitWidth: 10,
|
maxDigitWidth: 10,
|
||||||
}, true);
|
}, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public reserveHeight(height: number): void {
|
||||||
|
throw new Error('Not supported');
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
1
src/vs/monaco.d.ts
vendored
1
src/vs/monaco.d.ts
vendored
|
@ -5117,6 +5117,7 @@ declare namespace monaco.editor {
|
||||||
* Apply the same font settings as the editor to `target`.
|
* Apply the same font settings as the editor to `target`.
|
||||||
*/
|
*/
|
||||||
applyFontInfo(target: HTMLElement): void;
|
applyFontInfo(target: HTMLElement): void;
|
||||||
|
setBanner(bannerDomNode: HTMLElement | null, height: number): void;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -132,7 +132,7 @@ import { IEditorResolverService } from 'vs/workbench/services/editor/common/edit
|
||||||
import { IWorkingCopyEditorService, WorkingCopyEditorService } from 'vs/workbench/services/workingCopy/common/workingCopyEditorService';
|
import { IWorkingCopyEditorService, WorkingCopyEditorService } from 'vs/workbench/services/workingCopy/common/workingCopyEditorService';
|
||||||
import { IElevatedFileService } from 'vs/workbench/services/files/common/elevatedFileService';
|
import { IElevatedFileService } from 'vs/workbench/services/files/common/elevatedFileService';
|
||||||
import { BrowserElevatedFileService } from 'vs/workbench/services/files/browser/elevatedFileService';
|
import { BrowserElevatedFileService } from 'vs/workbench/services/files/browser/elevatedFileService';
|
||||||
import { IDiffComputationResult, IEditorWorkerService } from 'vs/editor/common/services/editorWorkerService';
|
import { IDiffComputationResult, IEditorWorkerService, IUnicodeHighlightsResult } from 'vs/editor/common/services/editorWorkerService';
|
||||||
import { TextEdit, IInplaceReplaceSupportResult } from 'vs/editor/common/modes';
|
import { TextEdit, IInplaceReplaceSupportResult } from 'vs/editor/common/modes';
|
||||||
import { ResourceMap } from 'vs/base/common/map';
|
import { ResourceMap } from 'vs/base/common/map';
|
||||||
import { SideBySideEditorInput } from 'vs/workbench/common/editor/sideBySideEditorInput';
|
import { SideBySideEditorInput } from 'vs/workbench/common/editor/sideBySideEditorInput';
|
||||||
|
@ -1866,7 +1866,7 @@ export class TestEditorWorkerService implements IEditorWorkerService {
|
||||||
declare readonly _serviceBrand: undefined;
|
declare readonly _serviceBrand: undefined;
|
||||||
|
|
||||||
canComputeUnicodeHighlights(uri: URI): boolean { return false; }
|
canComputeUnicodeHighlights(uri: URI): boolean { return false; }
|
||||||
async computedUnicodeHighlights(uri: URI): Promise<IRange[]> { return []; }
|
async computedUnicodeHighlights(uri: URI): Promise<IUnicodeHighlightsResult> { return { ranges: [], hasMore: false, ambiguousCharacterCount: 0, invisibleCharacterCount: 0, nonBasicAsciiCharacterCount: 0 }; }
|
||||||
async computeDiff(original: URI, modified: URI, ignoreTrimWhitespace: boolean, maxComputationTime: number): Promise<IDiffComputationResult | null> { return null; }
|
async computeDiff(original: URI, modified: URI, ignoreTrimWhitespace: boolean, maxComputationTime: number): Promise<IDiffComputationResult | null> { return null; }
|
||||||
canComputeDirtyDiff(original: URI, modified: URI): boolean { return false; }
|
canComputeDirtyDiff(original: URI, modified: URI): boolean { return false; }
|
||||||
async computeDirtyDiff(original: URI, modified: URI, ignoreTrimWhitespace: boolean): Promise<IChange[] | null> { return null; }
|
async computeDirtyDiff(original: URI, modified: URI, ignoreTrimWhitespace: boolean): Promise<IChange[] | null> { return null; }
|
||||||
|
|
Loading…
Reference in a new issue