mirror of
https://github.com/coder/code-server.git
synced 2026-05-09 05:47:26 +02:00
chore(vscode): update to 1.53.2
These conflicts will be resolved in the following commits. We do it this way so that PR review is possible.
This commit is contained in:
@@ -12,7 +12,7 @@ import { CharWidthRequest, CharWidthRequestType, readCharWidths } from 'vs/edito
|
||||
import { ElementSizeObserver } from 'vs/editor/browser/config/elementSizeObserver';
|
||||
import { CommonEditorConfiguration, IEnvConfiguration } from 'vs/editor/common/config/commonEditorConfig';
|
||||
import { EditorOption, EditorFontLigatures } from 'vs/editor/common/config/editorOptions';
|
||||
import { BareFontInfo, FontInfo } from 'vs/editor/common/config/fontInfo';
|
||||
import { BareFontInfo, FontInfo, SERIALIZED_FONT_INFO_VERSION } from 'vs/editor/common/config/fontInfo';
|
||||
import { IDimension } from 'vs/editor/common/editorCommon';
|
||||
import { IAccessibilityService, AccessibilitySupport } from 'vs/platform/accessibility/common/accessibility';
|
||||
import { IEditorConstructionOptions } from 'vs/editor/browser/editorBrowser';
|
||||
@@ -76,11 +76,13 @@ export function serializeFontInfo(): ISerializedFontInfo[] | null {
|
||||
}
|
||||
|
||||
export interface ISerializedFontInfo {
|
||||
readonly version: number;
|
||||
readonly zoomLevel: number;
|
||||
readonly pixelRatio: number;
|
||||
readonly fontFamily: string;
|
||||
readonly fontWeight: string;
|
||||
readonly fontSize: number;
|
||||
fontFeatureSettings: string;
|
||||
readonly fontFeatureSettings: string;
|
||||
readonly lineHeight: number;
|
||||
readonly letterSpacing: number;
|
||||
readonly isMonospace: boolean;
|
||||
@@ -88,8 +90,8 @@ export interface ISerializedFontInfo {
|
||||
readonly typicalFullwidthCharacterWidth: number;
|
||||
readonly canUseHalfwidthRightwardsArrow: boolean;
|
||||
readonly spaceWidth: number;
|
||||
middotWidth: number;
|
||||
wsmiddotWidth: number;
|
||||
readonly middotWidth: number;
|
||||
readonly wsmiddotWidth: number;
|
||||
readonly maxDigitWidth: number;
|
||||
}
|
||||
|
||||
@@ -138,8 +140,7 @@ class CSSBasedConfiguration extends Disposable {
|
||||
private _evictUntrustedReadings(): void {
|
||||
const values = this._cache.getValues();
|
||||
let somethingRemoved = false;
|
||||
for (let i = 0, len = values.length; i < len; i++) {
|
||||
const item = values[i];
|
||||
for (const item of values) {
|
||||
if (!item.isTrusted) {
|
||||
somethingRemoved = true;
|
||||
this._cache.remove(item);
|
||||
@@ -158,12 +159,11 @@ class CSSBasedConfiguration extends Disposable {
|
||||
public restoreFontInfo(savedFontInfos: ISerializedFontInfo[]): void {
|
||||
// Take all the saved font info and insert them in the cache without the trusted flag.
|
||||
// The reason for this is that a font might have been installed on the OS in the meantime.
|
||||
for (let i = 0, len = savedFontInfos.length; i < len; i++) {
|
||||
const savedFontInfo = savedFontInfos[i];
|
||||
// compatibility with older versions of VS Code which did not store this...
|
||||
savedFontInfo.fontFeatureSettings = savedFontInfo.fontFeatureSettings || EditorFontLigatures.OFF;
|
||||
savedFontInfo.middotWidth = savedFontInfo.middotWidth || savedFontInfo.spaceWidth;
|
||||
savedFontInfo.wsmiddotWidth = savedFontInfo.wsmiddotWidth || savedFontInfo.spaceWidth;
|
||||
for (const savedFontInfo of savedFontInfos) {
|
||||
if (savedFontInfo.version !== SERIALIZED_FONT_INFO_VERSION) {
|
||||
// cannot use older version
|
||||
continue;
|
||||
}
|
||||
const fontInfo = new FontInfo(savedFontInfo, false);
|
||||
this._writeToCache(fontInfo, fontInfo);
|
||||
}
|
||||
@@ -177,6 +177,7 @@ class CSSBasedConfiguration extends Disposable {
|
||||
// Hey, it's Bug 14341 ... we couldn't read
|
||||
readConfig = new FontInfo({
|
||||
zoomLevel: browser.getZoomLevel(),
|
||||
pixelRatio: browser.getPixelRatio(),
|
||||
fontFamily: readConfig.fontFamily,
|
||||
fontWeight: readConfig.fontWeight,
|
||||
fontSize: readConfig.fontSize,
|
||||
@@ -289,6 +290,7 @@ class CSSBasedConfiguration extends Disposable {
|
||||
const canTrustBrowserZoomLevel = (browser.getTimeSinceLastZoomLevelChanged() > 2000);
|
||||
return new FontInfo({
|
||||
zoomLevel: browser.getZoomLevel(),
|
||||
pixelRatio: browser.getPixelRatio(),
|
||||
fontFamily: bareFontInfo.fontFamily,
|
||||
fontWeight: bareFontInfo.fontWeight,
|
||||
fontSize: bareFontInfo.fontSize,
|
||||
@@ -331,15 +333,15 @@ export class Configuration extends CommonEditorConfiguration {
|
||||
|
||||
constructor(
|
||||
isSimpleWidget: boolean,
|
||||
options: IEditorConstructionOptions,
|
||||
options: Readonly<IEditorConstructionOptions>,
|
||||
referenceDomElement: HTMLElement | null = null,
|
||||
private readonly accessibilityService: IAccessibilityService
|
||||
) {
|
||||
super(isSimpleWidget, options);
|
||||
|
||||
this._elementSizeObserver = this._register(new ElementSizeObserver(referenceDomElement, options.dimension, () => this._onReferenceDomElementSizeChanged()));
|
||||
this._elementSizeObserver = this._register(new ElementSizeObserver(referenceDomElement, options.dimension, () => this._recomputeOptions()));
|
||||
|
||||
this._register(CSSBasedConfiguration.INSTANCE.onDidChange(() => this._onCSSBasedConfigurationChanged()));
|
||||
this._register(CSSBasedConfiguration.INSTANCE.onDidChange(() => this._recomputeOptions()));
|
||||
|
||||
if (this._validatedOptions.get(EditorOption.automaticLayout)) {
|
||||
this._elementSizeObserver.startObserving();
|
||||
@@ -351,28 +353,24 @@ export class Configuration extends CommonEditorConfiguration {
|
||||
this._recomputeOptions();
|
||||
}
|
||||
|
||||
private _onReferenceDomElementSizeChanged(): void {
|
||||
this._recomputeOptions();
|
||||
}
|
||||
|
||||
private _onCSSBasedConfigurationChanged(): void {
|
||||
this._recomputeOptions();
|
||||
}
|
||||
|
||||
public observeReferenceElement(dimension?: IDimension): void {
|
||||
this._elementSizeObserver.observe(dimension);
|
||||
}
|
||||
|
||||
public dispose(): void {
|
||||
super.dispose();
|
||||
public updatePixelRatio(): void {
|
||||
this._recomputeOptions();
|
||||
}
|
||||
|
||||
private _getExtraEditorClassName(): string {
|
||||
private static _getExtraEditorClassName(): string {
|
||||
let extra = '';
|
||||
if (!browser.isSafari && !browser.isWebkitWebView) {
|
||||
// Use user-select: none in all browsers except Safari and native macOS WebView
|
||||
extra += 'no-user-select ';
|
||||
}
|
||||
if (browser.isSafari) {
|
||||
// See https://github.com/microsoft/vscode/issues/108822
|
||||
extra += 'no-minimap-shadow ';
|
||||
}
|
||||
if (platform.isMacintosh) {
|
||||
extra += 'mac ';
|
||||
}
|
||||
@@ -381,7 +379,7 @@ export class Configuration extends CommonEditorConfiguration {
|
||||
|
||||
protected _getEnvConfiguration(): IEnvConfiguration {
|
||||
return {
|
||||
extraEditorClassName: this._getExtraEditorClassName(),
|
||||
extraEditorClassName: Configuration._getExtraEditorClassName(),
|
||||
outerWidth: this._elementSizeObserver.getWidth(),
|
||||
outerHeight: this._elementSizeObserver.getHeight(),
|
||||
emptySelectionClipboard: browser.isWebKit || browser.isFirefox,
|
||||
|
||||
@@ -110,7 +110,12 @@ export class MouseHandler extends ViewEventHandler {
|
||||
return;
|
||||
}
|
||||
const e = new StandardWheelEvent(browserEvent);
|
||||
if (e.browserEvent!.ctrlKey || e.browserEvent!.metaKey) {
|
||||
const doMouseWheelZoom = (
|
||||
platform.isMacintosh
|
||||
? (browserEvent.metaKey && !browserEvent.ctrlKey && !browserEvent.shiftKey && !browserEvent.altKey)
|
||||
: (browserEvent.ctrlKey && !browserEvent.metaKey && !browserEvent.shiftKey && !browserEvent.altKey)
|
||||
);
|
||||
if (doMouseWheelZoom) {
|
||||
const zoomLevel: number = EditorZoom.getZoomLevel();
|
||||
const delta = e.deltaY > 0 ? 1 : -1;
|
||||
EditorZoom.setZoomLevel(zoomLevel + delta);
|
||||
|
||||
@@ -269,11 +269,11 @@ export class HitTestContext {
|
||||
const viewZoneWhitespace = context.viewLayout.getWhitespaceAtVerticalOffset(mouseVerticalOffset);
|
||||
|
||||
if (viewZoneWhitespace) {
|
||||
let viewZoneMiddle = viewZoneWhitespace.verticalOffset + viewZoneWhitespace.height / 2,
|
||||
lineCount = context.model.getLineCount(),
|
||||
positionBefore: Position | null = null,
|
||||
position: Position | null,
|
||||
positionAfter: Position | null = null;
|
||||
const viewZoneMiddle = viewZoneWhitespace.verticalOffset + viewZoneWhitespace.height / 2;
|
||||
const lineCount = context.model.getLineCount();
|
||||
let positionBefore: Position | null = null;
|
||||
let position: Position | null;
|
||||
let positionAfter: Position | null = null;
|
||||
|
||||
if (viewZoneWhitespace.afterLineNumber !== lineCount) {
|
||||
// There are more lines after this view zone
|
||||
@@ -767,7 +767,7 @@ export class MouseTargetFactory {
|
||||
const lineWidth = ctx.getLineWidth(lineNumber);
|
||||
|
||||
if (request.mouseContentHorizontalOffset > lineWidth) {
|
||||
if (browser.isEdge && pos.column === 1) {
|
||||
if (browser.isEdgeLegacy && pos.column === 1) {
|
||||
// See https://github.com/microsoft/vscode/issues/10875
|
||||
const detail = createEmptyContentDataInLines(request.mouseContentHorizontalOffset - lineWidth);
|
||||
return request.fulfill(MouseTargetType.CONTENT_EMPTY, new Position(lineNumber, ctx.model.getLineMaxColumn(lineNumber)), undefined, detail);
|
||||
@@ -940,12 +940,16 @@ export class MouseTargetFactory {
|
||||
}
|
||||
}
|
||||
|
||||
// For inline decorations, Gecko returns the `<span>` of the line and the offset is the `<span>` with the inline decoration
|
||||
// For inline decorations, Gecko sometimes returns the `<span>` of the line and the offset is the `<span>` with the inline decoration
|
||||
// Some other times, it returns the `<span>` with the inline decoration
|
||||
if (hitResult.offsetNode.nodeType === hitResult.offsetNode.ELEMENT_NODE) {
|
||||
const parent1 = hitResult.offsetNode.parentNode; // expected to be the view line div
|
||||
const parent1 = hitResult.offsetNode.parentNode;
|
||||
const parent1ClassName = parent1 && parent1.nodeType === parent1.ELEMENT_NODE ? (<HTMLElement>parent1).className : null;
|
||||
const parent2 = parent1 ? parent1.parentNode : null;
|
||||
const parent2ClassName = parent2 && parent2.nodeType === parent2.ELEMENT_NODE ? (<HTMLElement>parent2).className : null;
|
||||
|
||||
if (parent1ClassName === ViewLine.CLASS_NAME) {
|
||||
// it returned the `<span>` of the line and the offset is the `<span>` with the inline decoration
|
||||
const tokenSpan = hitResult.offsetNode.childNodes[Math.min(hitResult.offset, hitResult.offsetNode.childNodes.length - 1)];
|
||||
if (tokenSpan) {
|
||||
const p = ctx.getPositionFromDOMInfo(<HTMLElement>tokenSpan, 0);
|
||||
@@ -954,6 +958,13 @@ export class MouseTargetFactory {
|
||||
hitTarget: null
|
||||
};
|
||||
}
|
||||
} else if (parent2ClassName === ViewLine.CLASS_NAME) {
|
||||
// it returned the `<span>` with the inline decoration
|
||||
const p = ctx.getPositionFromDOMInfo(<HTMLElement>hitResult.offsetNode, 0);
|
||||
return {
|
||||
position: p,
|
||||
hitTarget: null
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1014,12 +1025,11 @@ export class MouseTargetFactory {
|
||||
}
|
||||
|
||||
private static _snapToSoftTabBoundary(position: Position, viewModel: IViewModel): Position {
|
||||
const minColumn = viewModel.getLineMinColumn(position.lineNumber);
|
||||
const lineContent = viewModel.getLineContent(position.lineNumber);
|
||||
const { tabSize } = viewModel.getTextModelOptions();
|
||||
const newPosition = AtomicTabMoveOperations.atomicPosition(lineContent, position.column - minColumn, tabSize, Direction.Nearest);
|
||||
const newPosition = AtomicTabMoveOperations.atomicPosition(lineContent, position.column - 1, tabSize, Direction.Nearest);
|
||||
if (newPosition !== -1) {
|
||||
return new Position(position.lineNumber, newPosition + minColumn);
|
||||
return new Position(position.lineNumber, newPosition + 1);
|
||||
}
|
||||
return position;
|
||||
}
|
||||
|
||||
@@ -54,7 +54,7 @@ class VisibleTextAreaData {
|
||||
}
|
||||
}
|
||||
|
||||
const canUseZeroSizeTextarea = (browser.isEdge || browser.isFirefox);
|
||||
const canUseZeroSizeTextarea = (browser.isFirefox);
|
||||
|
||||
export class TextAreaHandler extends ViewPart {
|
||||
|
||||
@@ -280,14 +280,8 @@ export class TextAreaHandler extends ViewPart {
|
||||
}));
|
||||
|
||||
this._register(this._textAreaInput.onCompositionUpdate((e: ICompositionData) => {
|
||||
if (browser.isEdge) {
|
||||
// Due to isEdgeOrIE (where the textarea was not cleared initially)
|
||||
// we cannot assume the text consists only of the composited text
|
||||
this._visibleTextArea = this._visibleTextArea!.setWidth(0);
|
||||
} else {
|
||||
// adjust width by its size
|
||||
this._visibleTextArea = this._visibleTextArea!.setWidth(measureText(e.data, this._fontInfo));
|
||||
}
|
||||
// adjust width by its size
|
||||
this._visibleTextArea = this._visibleTextArea!.setWidth(measureText(e.data, this._fontInfo));
|
||||
this._render();
|
||||
}));
|
||||
|
||||
|
||||
@@ -13,7 +13,7 @@ import { KeyCode } from 'vs/base/common/keyCodes';
|
||||
import { Disposable, IDisposable } from 'vs/base/common/lifecycle';
|
||||
import * as platform from 'vs/base/common/platform';
|
||||
import * as strings from 'vs/base/common/strings';
|
||||
import { ITextAreaWrapper, ITypeData, TextAreaState } from 'vs/editor/browser/controller/textAreaState';
|
||||
import { ITextAreaWrapper, ITypeData, TextAreaState, _debugComposition } from 'vs/editor/browser/controller/textAreaState';
|
||||
import { Position } from 'vs/editor/common/core/position';
|
||||
import { Selection } from 'vs/editor/common/core/selection';
|
||||
import { BrowserFeatures } from 'vs/base/browser/canIUse';
|
||||
@@ -147,6 +147,7 @@ export class TextAreaInput extends Disposable {
|
||||
private readonly _host: ITextAreaInputHost;
|
||||
private readonly _textArea: TextAreaWrapper;
|
||||
private readonly _asyncTriggerCut: RunOnceScheduler;
|
||||
private readonly _asyncFocusGainWriteScreenReaderContent: RunOnceScheduler;
|
||||
|
||||
private _textAreaState: TextAreaState;
|
||||
private _selectionChangeListener: IDisposable | null;
|
||||
@@ -160,6 +161,7 @@ export class TextAreaInput extends Disposable {
|
||||
this._host = host;
|
||||
this._textArea = this._register(new TextAreaWrapper(textArea));
|
||||
this._asyncTriggerCut = this._register(new RunOnceScheduler(() => this._onCut.fire(), 0));
|
||||
this._asyncFocusGainWriteScreenReaderContent = this._register(new RunOnceScheduler(() => this.writeScreenReaderContent('asyncFocusGain'), 0));
|
||||
|
||||
this._textAreaState = TextAreaState.EMPTY;
|
||||
this._selectionChangeListener = null;
|
||||
@@ -193,6 +195,10 @@ export class TextAreaInput extends Disposable {
|
||||
}));
|
||||
|
||||
this._register(dom.addDisposableListener(textArea.domNode, 'compositionstart', (e: CompositionEvent) => {
|
||||
if (_debugComposition) {
|
||||
console.log(`[compositionstart]`, e);
|
||||
}
|
||||
|
||||
if (this._isDoingComposition) {
|
||||
return;
|
||||
}
|
||||
@@ -209,6 +215,9 @@ export class TextAreaInput extends Disposable {
|
||||
) {
|
||||
// Handling long press case on macOS + arrow key => pretend the character was selected
|
||||
if (lastKeyDown.code === 'ArrowRight' || lastKeyDown.code === 'ArrowLeft') {
|
||||
if (_debugComposition) {
|
||||
console.log(`[compositionstart] Handling long press case on macOS + arrow key`, e);
|
||||
}
|
||||
moveOneCharacterLeft = true;
|
||||
}
|
||||
}
|
||||
@@ -221,8 +230,7 @@ export class TextAreaInput extends Disposable {
|
||||
this._textAreaState.selectionStartPosition ? new Position(this._textAreaState.selectionStartPosition.lineNumber, this._textAreaState.selectionStartPosition.column - 1) : null,
|
||||
this._textAreaState.selectionEndPosition
|
||||
);
|
||||
} else if (!browser.isEdge) {
|
||||
// In IE we cannot set .value when handling 'compositionstart' because the entire composition will get canceled.
|
||||
} else {
|
||||
this._setAndWriteTextAreaState('compositionstart', TextAreaState.EMPTY);
|
||||
}
|
||||
|
||||
@@ -251,27 +259,10 @@ export class TextAreaInput extends Disposable {
|
||||
return [newState, typeInput];
|
||||
};
|
||||
|
||||
const compositionDataInValid = (locale: string): boolean => {
|
||||
// https://github.com/microsoft/monaco-editor/issues/339
|
||||
// Multi-part Japanese compositions reset cursor in Edge/IE, Chinese and Korean IME don't have this issue.
|
||||
// The reason that we can't use this path for all CJK IME is IE and Edge behave differently when handling Korean IME,
|
||||
// which breaks this path of code.
|
||||
if (browser.isEdge && locale === 'ja') {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
};
|
||||
|
||||
this._register(dom.addDisposableListener(textArea.domNode, 'compositionupdate', (e: CompositionEvent) => {
|
||||
if (compositionDataInValid(e.locale)) {
|
||||
const [newState, typeInput] = deduceInputFromTextAreaValue(/*couldBeEmojiInput*/false);
|
||||
this._textAreaState = newState;
|
||||
this._onType.fire(typeInput);
|
||||
this._onCompositionUpdate.fire(e);
|
||||
return;
|
||||
if (_debugComposition) {
|
||||
console.log(`[compositionupdate]`, e);
|
||||
}
|
||||
|
||||
const [newState, typeInput] = deduceComposition(e.data || '');
|
||||
this._textAreaState = newState;
|
||||
this._onType.fire(typeInput);
|
||||
@@ -279,28 +270,23 @@ export class TextAreaInput extends Disposable {
|
||||
}));
|
||||
|
||||
this._register(dom.addDisposableListener(textArea.domNode, 'compositionend', (e: CompositionEvent) => {
|
||||
if (_debugComposition) {
|
||||
console.log(`[compositionend]`, e);
|
||||
}
|
||||
// https://github.com/microsoft/monaco-editor/issues/1663
|
||||
// On iOS 13.2, Chinese system IME randomly trigger an additional compositionend event with empty data
|
||||
if (!this._isDoingComposition) {
|
||||
return;
|
||||
}
|
||||
if (compositionDataInValid(e.locale)) {
|
||||
// https://github.com/microsoft/monaco-editor/issues/339
|
||||
const [newState, typeInput] = deduceInputFromTextAreaValue(/*couldBeEmojiInput*/false);
|
||||
this._textAreaState = newState;
|
||||
this._onType.fire(typeInput);
|
||||
} else {
|
||||
const [newState, typeInput] = deduceComposition(e.data || '');
|
||||
this._textAreaState = newState;
|
||||
this._onType.fire(typeInput);
|
||||
}
|
||||
|
||||
// Due to
|
||||
// isEdgeOrIE (where the textarea was not cleared initially)
|
||||
// and isChrome (the textarea is not updated correctly when composition ends)
|
||||
// and isFirefox (the textare ais not updated correctly after inserting emojis)
|
||||
// we cannot assume the text at the end consists only of the composited text
|
||||
if (browser.isEdge || browser.isChrome || browser.isFirefox) {
|
||||
const [newState, typeInput] = deduceComposition(e.data || '');
|
||||
this._textAreaState = newState;
|
||||
this._onType.fire(typeInput);
|
||||
|
||||
// isChrome: the textarea is not updated correctly when composition ends
|
||||
// isFirefox: the textarea is not updated correctly after inserting emojis
|
||||
// => we cannot assume the text at the end consists only of the composited text
|
||||
if (browser.isChrome || browser.isFirefox) {
|
||||
this._textAreaState = TextAreaState.readFromTextArea(this._textArea);
|
||||
}
|
||||
|
||||
@@ -375,9 +361,31 @@ export class TextAreaInput extends Disposable {
|
||||
}));
|
||||
|
||||
this._register(dom.addDisposableListener(textArea.domNode, 'focus', () => {
|
||||
const hadFocus = this._hasFocus;
|
||||
|
||||
this._setHasFocus(true);
|
||||
|
||||
if (browser.isSafari && !hadFocus && this._hasFocus) {
|
||||
// When "tabbing into" the textarea, immediately after dispatching the 'focus' event,
|
||||
// Safari will always move the selection at offset 0 in the textarea
|
||||
this._asyncFocusGainWriteScreenReaderContent.schedule();
|
||||
}
|
||||
}));
|
||||
this._register(dom.addDisposableListener(textArea.domNode, 'blur', () => {
|
||||
if (this._isDoingComposition) {
|
||||
// See https://github.com/microsoft/vscode/issues/112621
|
||||
// where compositionend is not triggered when the editor
|
||||
// is taken off-dom during a composition
|
||||
|
||||
// Clear the flag to be able to write to the textarea
|
||||
this._isDoingComposition = false;
|
||||
|
||||
// Clear the textarea to avoid an unwanted cursor type
|
||||
this.writeScreenReaderContent('blurWithoutCompositionEnd');
|
||||
|
||||
// Fire artificial composition end
|
||||
this._onCompositionEnd.fire();
|
||||
}
|
||||
this._setHasFocus(false);
|
||||
}));
|
||||
}
|
||||
@@ -513,13 +521,7 @@ export class TextAreaInput extends Disposable {
|
||||
}
|
||||
|
||||
if (this._hasFocus) {
|
||||
if (browser.isEdge) {
|
||||
// Edge has a bug where setting the selection range while the focus event
|
||||
// is dispatching doesn't work. To reproduce, "tab into" the editor.
|
||||
this._setAndWriteTextAreaState('focusgain', TextAreaState.EMPTY);
|
||||
} else {
|
||||
this.writeScreenReaderContent('focusgain');
|
||||
}
|
||||
this.writeScreenReaderContent('focusgain');
|
||||
}
|
||||
|
||||
if (this._hasFocus) {
|
||||
|
||||
@@ -8,6 +8,8 @@ import { Position } from 'vs/editor/common/core/position';
|
||||
import { Range } from 'vs/editor/common/core/range';
|
||||
import { EndOfLinePreference } from 'vs/editor/common/model';
|
||||
|
||||
export const _debugComposition = false;
|
||||
|
||||
export interface ITextAreaWrapper {
|
||||
getValue(): string;
|
||||
setValue(reason: string, value: string): void;
|
||||
@@ -59,7 +61,9 @@ export class TextAreaState {
|
||||
}
|
||||
|
||||
public writeToTextArea(reason: string, textArea: ITextAreaWrapper, select: boolean): void {
|
||||
// console.log(Date.now() + ': writeToTextArea ' + reason + ': ' + this.toString());
|
||||
if (_debugComposition) {
|
||||
console.log('writeToTextArea ' + reason + ': ' + this.toString());
|
||||
}
|
||||
textArea.setValue(reason, this.value);
|
||||
if (select) {
|
||||
textArea.setSelectionRange(reason, this.selectionStart, this.selectionEnd);
|
||||
@@ -105,9 +109,11 @@ export class TextAreaState {
|
||||
};
|
||||
}
|
||||
|
||||
// console.log('------------------------deduceInput');
|
||||
// console.log('PREVIOUS STATE: ' + previousState.toString());
|
||||
// console.log('CURRENT STATE: ' + currentState.toString());
|
||||
if (_debugComposition) {
|
||||
console.log('------------------------deduceInput');
|
||||
console.log('PREVIOUS STATE: ' + previousState.toString());
|
||||
console.log('CURRENT STATE: ' + currentState.toString());
|
||||
}
|
||||
|
||||
let previousValue = previousState.value;
|
||||
let previousSelectionStart = previousState.selectionStart;
|
||||
@@ -133,8 +139,10 @@ export class TextAreaState {
|
||||
currentSelectionEnd -= prefixLength;
|
||||
previousSelectionEnd -= prefixLength;
|
||||
|
||||
// console.log('AFTER DIFFING PREVIOUS STATE: <' + previousValue + '>, selectionStart: ' + previousSelectionStart + ', selectionEnd: ' + previousSelectionEnd);
|
||||
// console.log('AFTER DIFFING CURRENT STATE: <' + currentValue + '>, selectionStart: ' + currentSelectionStart + ', selectionEnd: ' + currentSelectionEnd);
|
||||
if (_debugComposition) {
|
||||
console.log('AFTER DIFFING PREVIOUS STATE: <' + previousValue + '>, selectionStart: ' + previousSelectionStart + ', selectionEnd: ' + previousSelectionEnd);
|
||||
console.log('AFTER DIFFING CURRENT STATE: <' + currentValue + '>, selectionStart: ' + currentSelectionStart + ', selectionEnd: ' + currentSelectionEnd);
|
||||
}
|
||||
|
||||
if (couldBeEmojiInput && currentSelectionStart === currentSelectionEnd && previousValue.length > 0) {
|
||||
// on OSX, emojis from the emoji picker are inserted at random locations
|
||||
@@ -196,7 +204,9 @@ export class TextAreaState {
|
||||
|
||||
// no current selection
|
||||
const replacePreviousCharacters = (previousPrefix.length - prefixLength);
|
||||
// console.log('REMOVE PREVIOUS: ' + (previousPrefix.length - prefixLength) + ' chars');
|
||||
if (_debugComposition) {
|
||||
console.log('REMOVE PREVIOUS: ' + (previousPrefix.length - prefixLength) + ' chars');
|
||||
}
|
||||
|
||||
return {
|
||||
text: currentValue,
|
||||
|
||||
@@ -88,9 +88,7 @@ export class MarkdownRenderer {
|
||||
|
||||
const element = document.createElement('span');
|
||||
|
||||
element.innerHTML = MarkdownRenderer._ttpTokenizer
|
||||
? MarkdownRenderer._ttpTokenizer.createHTML(value, tokenization) as unknown as string
|
||||
: tokenizeToString(value, tokenization);
|
||||
element.innerHTML = (MarkdownRenderer._ttpTokenizer?.createHTML(value, tokenization) ?? tokenizeToString(value, tokenization)) as string;
|
||||
|
||||
// use "good" font
|
||||
let fontFamily = this._options.codeBlockFontFamily;
|
||||
@@ -105,7 +103,7 @@ export class MarkdownRenderer {
|
||||
},
|
||||
asyncRenderCallback: () => this._onDidRenderAsync.fire(),
|
||||
actionHandler: {
|
||||
callback: (content) => this._openerService.open(content, { fromUserGesture: true }).catch(onUnexpectedError),
|
||||
callback: (content) => this._openerService.open(content, { fromUserGesture: true, allowContributedOpeners: true }).catch(onUnexpectedError),
|
||||
disposeables
|
||||
}
|
||||
};
|
||||
|
||||
@@ -361,6 +361,11 @@ export interface IEditorConstructionOptions extends IEditorOptions {
|
||||
}
|
||||
|
||||
export interface IDiffEditorConstructionOptions extends IDiffEditorOptions {
|
||||
/**
|
||||
* The initial editor dimension (to avoid measuring the container).
|
||||
*/
|
||||
dimension?: editorCommon.IDimension;
|
||||
|
||||
/**
|
||||
* Place overflow widgets inside an external DOM node.
|
||||
* Defaults to an internal DOM node.
|
||||
@@ -1047,7 +1052,7 @@ export interface IDiffEditor extends editorCommon.IEditor {
|
||||
/**
|
||||
*@internal
|
||||
*/
|
||||
export function isCodeEditor(thing: any): thing is ICodeEditor {
|
||||
export function isCodeEditor(thing: unknown): thing is ICodeEditor {
|
||||
if (thing && typeof (<ICodeEditor>thing).getEditorType === 'function') {
|
||||
return (<ICodeEditor>thing).getEditorType() === editorCommon.EditorType.ICodeEditor;
|
||||
} else {
|
||||
@@ -1058,7 +1063,7 @@ export function isCodeEditor(thing: any): thing is ICodeEditor {
|
||||
/**
|
||||
*@internal
|
||||
*/
|
||||
export function isDiffEditor(thing: any): thing is IDiffEditor {
|
||||
export function isDiffEditor(thing: unknown): thing is IDiffEditor {
|
||||
if (thing && typeof (<IDiffEditor>thing).getEditorType === 'function') {
|
||||
return (<IDiffEditor>thing).getEditorType() === editorCommon.EditorType.IDiffEditor;
|
||||
} else {
|
||||
@@ -1069,8 +1074,8 @@ export function isDiffEditor(thing: any): thing is IDiffEditor {
|
||||
/**
|
||||
*@internal
|
||||
*/
|
||||
export function isCompositeEditor(thing: any): thing is editorCommon.ICompositeCodeEditor {
|
||||
return thing
|
||||
export function isCompositeEditor(thing: unknown): thing is editorCommon.ICompositeCodeEditor {
|
||||
return !!thing
|
||||
&& typeof thing === 'object'
|
||||
&& typeof (<editorCommon.ICompositeCodeEditor>thing).onDidChangeActiveEditor === 'function';
|
||||
|
||||
@@ -1079,7 +1084,7 @@ export function isCompositeEditor(thing: any): thing is editorCommon.ICompositeC
|
||||
/**
|
||||
*@internal
|
||||
*/
|
||||
export function getCodeEditor(thing: any): ICodeEditor | null {
|
||||
export function getCodeEditor(thing: unknown): ICodeEditor | null {
|
||||
if (isCodeEditor(thing)) {
|
||||
return thing;
|
||||
}
|
||||
|
||||
@@ -69,11 +69,11 @@ export interface IBulkEditOptions {
|
||||
progress?: IProgress<IProgressStep>;
|
||||
token?: CancellationToken;
|
||||
showPreview?: boolean;
|
||||
suppressPreview?: boolean;
|
||||
label?: string;
|
||||
quotableLabel?: string;
|
||||
undoRedoSource?: UndoRedoSource;
|
||||
undoRedoGroupId?: number;
|
||||
confirmBeforeUndo?: boolean;
|
||||
}
|
||||
|
||||
export interface IBulkEditResult {
|
||||
|
||||
@@ -347,6 +347,8 @@ const _CSS_MAP: { [prop: string]: string; } = {
|
||||
|
||||
fontStyle: 'font-style:{0};',
|
||||
fontWeight: 'font-weight:{0};',
|
||||
fontSize: 'font-size:{0};',
|
||||
fontFamily: 'font-family:{0};',
|
||||
textDecoration: 'text-decoration:{0};',
|
||||
cursor: 'cursor:{0};',
|
||||
letterSpacing: 'letter-spacing:{0};',
|
||||
@@ -357,6 +359,7 @@ const _CSS_MAP: { [prop: string]: string; } = {
|
||||
contentText: 'content:\'{0}\';',
|
||||
contentIconPath: 'content:{0};',
|
||||
margin: 'margin:{0};',
|
||||
padding: 'padding:{0};',
|
||||
width: 'width:{0};',
|
||||
height: 'height:{0};'
|
||||
};
|
||||
@@ -529,7 +532,7 @@ class DecorationCSSRules {
|
||||
|
||||
cssTextArr.push(strings.format(_CSS_MAP.contentText, escaped));
|
||||
}
|
||||
this.collectCSSText(opts, ['fontStyle', 'fontWeight', 'textDecoration', 'color', 'opacity', 'backgroundColor', 'margin'], cssTextArr);
|
||||
this.collectCSSText(opts, ['fontStyle', 'fontWeight', 'fontSize', 'fontFamily', 'textDecoration', 'color', 'opacity', 'backgroundColor', 'margin', 'padding'], cssTextArr);
|
||||
if (this.collectCSSText(opts, ['width', 'height'], cssTextArr)) {
|
||||
cssTextArr.push('display:inline-block;');
|
||||
}
|
||||
|
||||
@@ -4,18 +4,18 @@
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import * as dom from 'vs/base/browser/dom';
|
||||
import { CancellationToken } from 'vs/base/common/cancellation';
|
||||
import { IDisposable } from 'vs/base/common/lifecycle';
|
||||
import { LinkedList } from 'vs/base/common/linkedList';
|
||||
import { ResourceMap } from 'vs/base/common/map';
|
||||
import { parse } from 'vs/base/common/marshalling';
|
||||
import { Schemas } from 'vs/base/common/network';
|
||||
import { normalizePath } from 'vs/base/common/resources';
|
||||
import { URI } from 'vs/base/common/uri';
|
||||
import { ICodeEditorService } from 'vs/editor/browser/services/codeEditorService';
|
||||
import { ICommandService } from 'vs/platform/commands/common/commands';
|
||||
import { IOpener, IOpenerService, IValidator, IExternalUriResolver, OpenOptions, ResolveExternalUriOptions, IResolvedExternalUri, IExternalOpener, matchesScheme } from 'vs/platform/opener/common/opener';
|
||||
import { EditorOpenContext } from 'vs/platform/editor/common/editor';
|
||||
import { ResourceMap } from 'vs/base/common/map';
|
||||
|
||||
import { IExternalOpener, IExternalUriResolver, IOpener, IOpenerService, IResolvedExternalUri, IValidator, matchesScheme, OpenOptions, ResolveExternalUriOptions } from 'vs/platform/opener/common/opener';
|
||||
|
||||
class CommandOpener implements IOpener {
|
||||
|
||||
@@ -100,15 +100,16 @@ export class OpenerService implements IOpenerService {
|
||||
private readonly _resolvers = new LinkedList<IExternalUriResolver>();
|
||||
private readonly _resolvedUriTargets = new ResourceMap<URI>(uri => uri.with({ path: null, fragment: null, query: null }).toString());
|
||||
|
||||
private _externalOpener: IExternalOpener;
|
||||
private _defaultExternalOpener: IExternalOpener;
|
||||
private readonly _externalOpeners = new LinkedList<IExternalOpener>();
|
||||
|
||||
constructor(
|
||||
@ICodeEditorService editorService: ICodeEditorService,
|
||||
@ICommandService commandService: ICommandService,
|
||||
) {
|
||||
// Default external opener is going through window.open()
|
||||
this._externalOpener = {
|
||||
openExternal: href => {
|
||||
this._defaultExternalOpener = {
|
||||
openExternal: async href => {
|
||||
// ensure to open HTTP/HTTPS links into new windows
|
||||
// to not trigger a navigation. Any other link is
|
||||
// safe to be set as HREF to prevent a blank window
|
||||
@@ -118,11 +119,11 @@ export class OpenerService implements IOpenerService {
|
||||
} else {
|
||||
window.location.href = href;
|
||||
}
|
||||
return Promise.resolve(true);
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
// Default opener: maito, http(s), command, and catch-all-editors
|
||||
// Default opener: any external, maito, http(s), command, and catch-all-editors
|
||||
this._openers.push({
|
||||
open: async (target: URI | string, options?: OpenOptions) => {
|
||||
if (options?.openExternal || matchesScheme(target, Schemas.mailto) || matchesScheme(target, Schemas.http) || matchesScheme(target, Schemas.https)) {
|
||||
@@ -152,8 +153,13 @@ export class OpenerService implements IOpenerService {
|
||||
return { dispose: remove };
|
||||
}
|
||||
|
||||
setExternalOpener(externalOpener: IExternalOpener): void {
|
||||
this._externalOpener = externalOpener;
|
||||
setDefaultExternalOpener(externalOpener: IExternalOpener): void {
|
||||
this._defaultExternalOpener = externalOpener;
|
||||
}
|
||||
|
||||
registerExternalOpener(opener: IExternalOpener): IDisposable {
|
||||
const remove = this._externalOpeners.push(opener);
|
||||
return { dispose: remove };
|
||||
}
|
||||
|
||||
async open(target: URI | string, options?: OpenOptions): Promise<boolean> {
|
||||
@@ -196,13 +202,29 @@ export class OpenerService implements IOpenerService {
|
||||
const uri = typeof resource === 'string' ? URI.parse(resource) : resource;
|
||||
const { resolved } = await this.resolveExternalUri(uri, options);
|
||||
|
||||
let href: string;
|
||||
if (typeof resource === 'string' && uri.toString() === resolved.toString()) {
|
||||
// open the url-string AS IS
|
||||
return this._externalOpener.openExternal(resource);
|
||||
href = resource;
|
||||
} else {
|
||||
// open URI using the toString(noEncode)+encodeURI-trick
|
||||
return this._externalOpener.openExternal(encodeURI(resolved.toString(true)));
|
||||
href = encodeURI(resolved.toString(true));
|
||||
}
|
||||
|
||||
if (options?.allowContributedOpeners) {
|
||||
const preferredOpenerId = typeof options?.allowContributedOpeners === 'string' ? options?.allowContributedOpeners : undefined;
|
||||
for (const opener of this._externalOpeners) {
|
||||
const didOpen = await opener.openExternal(href, {
|
||||
sourceUri: uri,
|
||||
preferredOpenerId,
|
||||
}, CancellationToken.None);
|
||||
if (didOpen) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return this._defaultExternalOpener.openExternal(href, { sourceUri: uri }, CancellationToken.None);
|
||||
}
|
||||
|
||||
dispose() {
|
||||
|
||||
@@ -111,8 +111,8 @@ function createLineBreaks(requests: string[], fontInfo: FontInfo, tabSize: numbe
|
||||
allVisibleColumns[i] = tmp[1];
|
||||
}
|
||||
const html = sb.build();
|
||||
const trustedhtml = ttPolicy ? ttPolicy.createHTML(html) : html;
|
||||
containerDomNode.innerHTML = trustedhtml as unknown as string;
|
||||
const trustedhtml = ttPolicy?.createHTML(html) ?? html;
|
||||
containerDomNode.innerHTML = trustedhtml as string;
|
||||
|
||||
containerDomNode.style.position = 'absolute';
|
||||
containerDomNode.style.top = '10000';
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import * as dom from 'vs/base/browser/dom';
|
||||
import * as browser from 'vs/base/browser/browser';
|
||||
import { Selection } from 'vs/editor/common/core/selection';
|
||||
import { FastDomNode, createFastDomNode } from 'vs/base/browser/fastDomNode';
|
||||
import { IMouseEvent } from 'vs/base/browser/mouseEvent';
|
||||
@@ -65,6 +66,7 @@ export class View extends ViewEventHandler {
|
||||
|
||||
private readonly _scrollbar: EditorScrollbar;
|
||||
private readonly _context: ViewContext;
|
||||
private _configPixelRatio: number;
|
||||
private _selections: Selection[];
|
||||
|
||||
// The view lines
|
||||
@@ -104,6 +106,7 @@ export class View extends ViewEventHandler {
|
||||
|
||||
// The view context is passed on to most classes (basically to reduce param. counts in ctors)
|
||||
this._context = new ViewContext(configuration, themeService.getColorTheme(), model);
|
||||
this._configPixelRatio = this._configPixelRatio = this._context.configuration.options.get(EditorOption.pixelRatio);
|
||||
|
||||
// Ensure the view is the first event handler in order to update the layout
|
||||
this._context.addEventHandler(this);
|
||||
@@ -298,6 +301,7 @@ export class View extends ViewEventHandler {
|
||||
this._scheduleRender();
|
||||
}
|
||||
public onConfigurationChanged(e: viewEvents.ViewConfigurationChangedEvent): boolean {
|
||||
this._configPixelRatio = this._context.configuration.options.get(EditorOption.pixelRatio);
|
||||
this.domNode.setClassName(this._getEditorClassName());
|
||||
this._applyLayout();
|
||||
return false;
|
||||
@@ -330,8 +334,8 @@ export class View extends ViewEventHandler {
|
||||
this._viewLines.dispose();
|
||||
|
||||
// Destroy view parts
|
||||
for (let i = 0, len = this._viewParts.length; i < len; i++) {
|
||||
this._viewParts[i].dispose();
|
||||
for (const viewPart of this._viewParts) {
|
||||
viewPart.dispose();
|
||||
}
|
||||
|
||||
super.dispose();
|
||||
@@ -354,8 +358,7 @@ export class View extends ViewEventHandler {
|
||||
|
||||
private _getViewPartsToRender(): ViewPart[] {
|
||||
let result: ViewPart[] = [], resultLen = 0;
|
||||
for (let i = 0, len = this._viewParts.length; i < len; i++) {
|
||||
const viewPart = this._viewParts[i];
|
||||
for (const viewPart of this._viewParts) {
|
||||
if (viewPart.shouldRender()) {
|
||||
result[resultLen++] = viewPart;
|
||||
}
|
||||
@@ -401,16 +404,20 @@ export class View extends ViewEventHandler {
|
||||
const renderingContext = new RenderingContext(this._context.viewLayout, viewportData, this._viewLines);
|
||||
|
||||
// Render the rest of the parts
|
||||
for (let i = 0, len = viewPartsToRender.length; i < len; i++) {
|
||||
const viewPart = viewPartsToRender[i];
|
||||
for (const viewPart of viewPartsToRender) {
|
||||
viewPart.prepareRender(renderingContext);
|
||||
}
|
||||
|
||||
for (let i = 0, len = viewPartsToRender.length; i < len; i++) {
|
||||
const viewPart = viewPartsToRender[i];
|
||||
for (const viewPart of viewPartsToRender) {
|
||||
viewPart.render(renderingContext);
|
||||
viewPart.onDidRender();
|
||||
}
|
||||
|
||||
// Try to detect browser zooming and paint again if necessary
|
||||
if (Math.abs(browser.getPixelRatio() - this._configPixelRatio) > 0.001) {
|
||||
// looks like the pixel ratio has changed
|
||||
this._context.configuration.updatePixelRatio();
|
||||
}
|
||||
}
|
||||
|
||||
// --- BEGIN CodeEditor helpers
|
||||
@@ -462,8 +469,7 @@ export class View extends ViewEventHandler {
|
||||
if (everything) {
|
||||
// Force everything to render...
|
||||
this._viewLines.forceShouldRender();
|
||||
for (let i = 0, len = this._viewParts.length; i < len; i++) {
|
||||
const viewPart = this._viewParts[i];
|
||||
for (const viewPart of this._viewParts) {
|
||||
viewPart.forceShouldRender();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -506,15 +506,15 @@ class ViewLayerRenderer<T extends IVisibleLine> {
|
||||
ctx.lines.splice(removeIndex, removeCount);
|
||||
}
|
||||
|
||||
private _finishRenderingNewLines(ctx: IRendererContext<T>, domNodeIsEmpty: boolean, newLinesHTML: string, wasNew: boolean[]): void {
|
||||
private _finishRenderingNewLines(ctx: IRendererContext<T>, domNodeIsEmpty: boolean, newLinesHTML: string | TrustedHTML, wasNew: boolean[]): void {
|
||||
if (ViewLayerRenderer._ttPolicy) {
|
||||
newLinesHTML = ViewLayerRenderer._ttPolicy.createHTML(newLinesHTML) as unknown as string; // explains the ugly casts -> https://github.com/microsoft/vscode/issues/106396#issuecomment-692625393
|
||||
newLinesHTML = ViewLayerRenderer._ttPolicy.createHTML(newLinesHTML as string);
|
||||
}
|
||||
const lastChild = <HTMLElement>this.domNode.lastChild;
|
||||
if (domNodeIsEmpty || !lastChild) {
|
||||
this.domNode.innerHTML = newLinesHTML;
|
||||
this.domNode.innerHTML = newLinesHTML as string; // explains the ugly casts -> https://github.com/microsoft/vscode/issues/106396#issuecomment-692625393;
|
||||
} else {
|
||||
lastChild.insertAdjacentHTML('afterend', newLinesHTML);
|
||||
lastChild.insertAdjacentHTML('afterend', newLinesHTML as string);
|
||||
}
|
||||
|
||||
let currChild = <HTMLElement>this.domNode.lastChild;
|
||||
@@ -527,13 +527,13 @@ class ViewLayerRenderer<T extends IVisibleLine> {
|
||||
}
|
||||
}
|
||||
|
||||
private _finishRenderingInvalidLines(ctx: IRendererContext<T>, invalidLinesHTML: string, wasInvalid: boolean[]): void {
|
||||
private _finishRenderingInvalidLines(ctx: IRendererContext<T>, invalidLinesHTML: string | TrustedHTML, wasInvalid: boolean[]): void {
|
||||
const hugeDomNode = document.createElement('div');
|
||||
|
||||
if (ViewLayerRenderer._ttPolicy) {
|
||||
invalidLinesHTML = ViewLayerRenderer._ttPolicy.createHTML(invalidLinesHTML) as unknown as string;
|
||||
invalidLinesHTML = ViewLayerRenderer._ttPolicy.createHTML(invalidLinesHTML as string);
|
||||
}
|
||||
hugeDomNode.innerHTML = invalidLinesHTML;
|
||||
hugeDomNode.innerHTML = invalidLinesHTML as string;
|
||||
|
||||
for (let i = 0; i < ctx.linesLength; i++) {
|
||||
const line = ctx.lines[i];
|
||||
|
||||
@@ -42,8 +42,8 @@ export abstract class AbstractLineHighlightOverlay extends DynamicViewOverlay {
|
||||
this._contentWidth = layoutInfo.contentWidth;
|
||||
this._selectionIsEmpty = true;
|
||||
this._focused = false;
|
||||
this._cursorLineNumbers = [];
|
||||
this._selections = [];
|
||||
this._cursorLineNumbers = [1];
|
||||
this._selections = [new Selection(1, 1, 1, 1)];
|
||||
this._renderData = null;
|
||||
|
||||
this._context.addEventHandler(this);
|
||||
|
||||
@@ -44,7 +44,7 @@ const canUseFastRenderedViewLine = (function () {
|
||||
|
||||
let monospaceAssumptionsAreValid = true;
|
||||
|
||||
const alwaysRenderInlineSelection = (browser.isEdge);
|
||||
const alwaysRenderInlineSelection = (browser.isEdgeLegacy);
|
||||
|
||||
export class DomReadingContext {
|
||||
|
||||
|
||||
@@ -25,3 +25,8 @@
|
||||
left: -6px;
|
||||
width: 6px;
|
||||
}
|
||||
.monaco-editor.no-minimap-shadow .minimap-shadow-visible {
|
||||
position: absolute;
|
||||
left: -1px;
|
||||
width: 1px;
|
||||
}
|
||||
|
||||
@@ -862,6 +862,7 @@ export class Minimap extends ViewPart implements IMinimapModel {
|
||||
}
|
||||
}
|
||||
public onTokensColorsChanged(e: viewEvents.ViewTokensColorsChangedEvent): boolean {
|
||||
this._onOptionsMaybeChanged();
|
||||
return this._actual.onTokensColorsChanged();
|
||||
}
|
||||
public onZonesChanged(e: viewEvents.ViewZonesChangedEvent): boolean {
|
||||
|
||||
@@ -60,7 +60,7 @@ function toStyled(item: LineVisibleRanges): LineVisibleRangesWithStyle {
|
||||
// TODO@Alex: Remove this once IE11 fixes Bug #524217
|
||||
// The problem in IE11 is that it does some sort of auto-zooming to accomodate for displays with different pixel density.
|
||||
// Unfortunately, this auto-zooming is buggy around dealing with rounded borders
|
||||
const isIEWithZoomingIssuesNearRoundedBorders = browser.isEdge;
|
||||
const isIEWithZoomingIssuesNearRoundedBorders = browser.isEdgeLegacy;
|
||||
|
||||
|
||||
export class SelectionsOverlay extends DynamicViewOverlay {
|
||||
|
||||
@@ -24,7 +24,7 @@ import { ViewUserInputEvents } from 'vs/editor/browser/view/viewUserInputEvents'
|
||||
import { ConfigurationChangedEvent, EditorLayoutInfo, IEditorOptions, EditorOption, IComputedEditorOptions, FindComputedEditorOptionValueById, filterValidationDecorations } from 'vs/editor/common/config/editorOptions';
|
||||
import { Cursor } from 'vs/editor/common/controller/cursor';
|
||||
import { CursorColumns } from 'vs/editor/common/controller/cursorCommon';
|
||||
import { ICursorPositionChangedEvent, ICursorSelectionChangedEvent } from 'vs/editor/common/controller/cursorEvents';
|
||||
import { CursorChangeReason, ICursorPositionChangedEvent, ICursorSelectionChangedEvent } from 'vs/editor/common/controller/cursorEvents';
|
||||
import { IPosition, Position } from 'vs/editor/common/core/position';
|
||||
import { IRange, Range } from 'vs/editor/common/core/range';
|
||||
import { ISelection, Selection } from 'vs/editor/common/core/selection';
|
||||
@@ -241,7 +241,7 @@ export class CodeEditorWidget extends Disposable implements editorBrowser.ICodeE
|
||||
|
||||
constructor(
|
||||
domElement: HTMLElement,
|
||||
options: editorBrowser.IEditorConstructionOptions,
|
||||
_options: Readonly<editorBrowser.IEditorConstructionOptions>,
|
||||
codeEditorWidgetOptions: ICodeEditorWidgetOptions,
|
||||
@IInstantiationService instantiationService: IInstantiationService,
|
||||
@ICodeEditorService codeEditorService: ICodeEditorService,
|
||||
@@ -253,10 +253,11 @@ export class CodeEditorWidget extends Disposable implements editorBrowser.ICodeE
|
||||
) {
|
||||
super();
|
||||
|
||||
options = options || {};
|
||||
const options = { ..._options };
|
||||
|
||||
this._domElement = domElement;
|
||||
this._overflowWidgetsDomNode = options.overflowWidgetsDomNode;
|
||||
delete options.overflowWidgetsDomNode;
|
||||
this._id = (++EDITOR_ID);
|
||||
this._decorationTypeKeysToIds = {};
|
||||
this._decorationTypeSubtypes = {};
|
||||
@@ -331,7 +332,7 @@ export class CodeEditorWidget extends Disposable implements editorBrowser.ICodeE
|
||||
this._codeEditorService.addCodeEditor(this);
|
||||
}
|
||||
|
||||
protected _createConfiguration(options: editorBrowser.IEditorConstructionOptions, accessibilityService: IAccessibilityService): editorCommon.IConfiguration {
|
||||
protected _createConfiguration(options: Readonly<editorBrowser.IEditorConstructionOptions>, accessibilityService: IAccessibilityService): editorCommon.IConfiguration {
|
||||
return new Configuration(this.isSimpleWidget, options, this._domElement, accessibilityService);
|
||||
}
|
||||
|
||||
@@ -366,7 +367,7 @@ export class CodeEditorWidget extends Disposable implements editorBrowser.ICodeE
|
||||
return this._instantiationService.invokeFunction(fn);
|
||||
}
|
||||
|
||||
public updateOptions(newOptions: IEditorOptions): void {
|
||||
public updateOptions(newOptions: Readonly<IEditorOptions>): void {
|
||||
this._configuration.updateOptions(newOptions);
|
||||
}
|
||||
|
||||
@@ -811,7 +812,7 @@ export class CodeEditorWidget extends Disposable implements editorBrowser.ICodeE
|
||||
);
|
||||
}
|
||||
|
||||
public setSelections(ranges: readonly ISelection[], source: string = 'api'): void {
|
||||
public setSelections(ranges: readonly ISelection[], source: string = 'api', reason = CursorChangeReason.NotSet): void {
|
||||
if (!this._modelData) {
|
||||
return;
|
||||
}
|
||||
@@ -823,7 +824,7 @@ export class CodeEditorWidget extends Disposable implements editorBrowser.ICodeE
|
||||
throw new Error('Invalid arguments');
|
||||
}
|
||||
}
|
||||
this._modelData.viewModel.setSelections(source, ranges);
|
||||
this._modelData.viewModel.setSelections(source, ranges, reason);
|
||||
}
|
||||
|
||||
public getContentWidth(): number {
|
||||
@@ -1834,6 +1835,7 @@ export class EditorModeContext extends Disposable {
|
||||
private readonly _hasMultipleDocumentFormattingProvider: IContextKey<boolean>;
|
||||
private readonly _hasMultipleDocumentSelectionFormattingProvider: IContextKey<boolean>;
|
||||
private readonly _hasSignatureHelpProvider: IContextKey<boolean>;
|
||||
private readonly _hasInlineHintsProvider: IContextKey<boolean>;
|
||||
private readonly _isInWalkThrough: IContextKey<boolean>;
|
||||
|
||||
constructor(
|
||||
@@ -1856,6 +1858,7 @@ export class EditorModeContext extends Disposable {
|
||||
this._hasReferenceProvider = EditorContextKeys.hasReferenceProvider.bindTo(_contextKeyService);
|
||||
this._hasRenameProvider = EditorContextKeys.hasRenameProvider.bindTo(_contextKeyService);
|
||||
this._hasSignatureHelpProvider = EditorContextKeys.hasSignatureHelpProvider.bindTo(_contextKeyService);
|
||||
this._hasInlineHintsProvider = EditorContextKeys.hasInlineHintsProvider.bindTo(_contextKeyService);
|
||||
this._hasDocumentFormattingProvider = EditorContextKeys.hasDocumentFormattingProvider.bindTo(_contextKeyService);
|
||||
this._hasDocumentSelectionFormattingProvider = EditorContextKeys.hasDocumentSelectionFormattingProvider.bindTo(_contextKeyService);
|
||||
this._hasMultipleDocumentFormattingProvider = EditorContextKeys.hasMultipleDocumentFormattingProvider.bindTo(_contextKeyService);
|
||||
@@ -1884,6 +1887,7 @@ export class EditorModeContext extends Disposable {
|
||||
this._register(modes.DocumentFormattingEditProviderRegistry.onDidChange(update));
|
||||
this._register(modes.DocumentRangeFormattingEditProviderRegistry.onDidChange(update));
|
||||
this._register(modes.SignatureHelpProviderRegistry.onDidChange(update));
|
||||
this._register(modes.InlineHintsProviderRegistry.onDidChange(update));
|
||||
|
||||
update();
|
||||
}
|
||||
@@ -1935,6 +1939,7 @@ export class EditorModeContext extends Disposable {
|
||||
this._hasReferenceProvider.set(modes.ReferenceProviderRegistry.has(model));
|
||||
this._hasRenameProvider.set(modes.RenameProviderRegistry.has(model));
|
||||
this._hasSignatureHelpProvider.set(modes.SignatureHelpProviderRegistry.has(model));
|
||||
this._hasInlineHintsProvider.set(modes.InlineHintsProviderRegistry.has(model));
|
||||
this._hasDocumentFormattingProvider.set(modes.DocumentFormattingEditProviderRegistry.has(model) || modes.DocumentRangeFormattingEditProviderRegistry.has(model));
|
||||
this._hasDocumentSelectionFormattingProvider.set(modes.DocumentRangeFormattingEditProviderRegistry.has(model));
|
||||
this._hasMultipleDocumentFormattingProvider.set(modes.DocumentFormattingEditProviderRegistry.all(model).length + modes.DocumentRangeFormattingEditProviderRegistry.all(model).length > 1);
|
||||
|
||||
@@ -12,15 +12,14 @@ import { RunOnceScheduler } from 'vs/base/common/async';
|
||||
import { Color } from 'vs/base/common/color';
|
||||
import { Emitter, Event } from 'vs/base/common/event';
|
||||
import { Disposable } from 'vs/base/common/lifecycle';
|
||||
import * as objects from 'vs/base/common/objects';
|
||||
import { URI } from 'vs/base/common/uri';
|
||||
import { Configuration } from 'vs/editor/browser/config/configuration';
|
||||
import { StableEditorScrollState } from 'vs/editor/browser/core/editorState';
|
||||
import * as editorBrowser from 'vs/editor/browser/editorBrowser';
|
||||
import { ICodeEditorService } from 'vs/editor/browser/services/codeEditorService';
|
||||
import { CodeEditorWidget } from 'vs/editor/browser/widget/codeEditorWidget';
|
||||
import { CodeEditorWidget, ICodeEditorWidgetOptions } from 'vs/editor/browser/widget/codeEditorWidget';
|
||||
import { DiffReview } from 'vs/editor/browser/widget/diffReview';
|
||||
import { IDiffEditorOptions, IEditorOptions, EditorLayoutInfo, EditorOption, EditorOptions, EditorFontLigatures, stringSet as validateStringSetOption, boolean as validateBooleanOption } from 'vs/editor/common/config/editorOptions';
|
||||
import { IDiffEditorOptions, EditorLayoutInfo, EditorOption, EditorOptions, EditorFontLigatures, stringSet as validateStringSetOption, boolean as validateBooleanOption } from 'vs/editor/common/config/editorOptions';
|
||||
import { IPosition, Position } from 'vs/editor/common/core/position';
|
||||
import { IRange, Range } from 'vs/editor/common/core/range';
|
||||
import { ISelection, Selection } from 'vs/editor/common/core/selection';
|
||||
@@ -54,6 +53,11 @@ import { IViewLineTokens } from 'vs/editor/common/core/lineTokens';
|
||||
import { FontInfo } from 'vs/editor/common/config/fontInfo';
|
||||
import { registerIcon } from 'vs/platform/theme/common/iconRegistry';
|
||||
|
||||
export interface IDiffCodeEditorWidgetOptions {
|
||||
originalEditor?: ICodeEditorWidgetOptions;
|
||||
modifiedEditor?: ICodeEditorWidgetOptions;
|
||||
}
|
||||
|
||||
interface IEditorDiffDecorations {
|
||||
decorations: IModelDeltaDecoration[];
|
||||
overviewZones: OverviewRulerZone[];
|
||||
@@ -109,7 +113,7 @@ class VisualEditorState {
|
||||
this._decorations = editor.deltaDecorations(this._decorations, []);
|
||||
}
|
||||
|
||||
public apply(editor: CodeEditorWidget, overviewRuler: editorBrowser.IOverviewRuler, newDecorations: IEditorDiffDecorationsWithZones, restoreScrollState: boolean): void {
|
||||
public apply(editor: CodeEditorWidget, overviewRuler: editorBrowser.IOverviewRuler | null, newDecorations: IEditorDiffDecorationsWithZones, restoreScrollState: boolean): void {
|
||||
|
||||
const scrollState = restoreScrollState ? StableEditorScrollState.capture(editor) : null;
|
||||
|
||||
@@ -212,6 +216,7 @@ export class DiffEditorWidget extends Disposable implements editorBrowser.IDiffE
|
||||
private _maxComputationTime: number;
|
||||
private _renderIndicators: boolean;
|
||||
private _enableSplitViewResizing: boolean;
|
||||
private _renderOverviewRuler: boolean;
|
||||
private _strategy!: DiffEditorWidgetStyle;
|
||||
|
||||
private readonly _updateDecorationsRunner: RunOnceScheduler;
|
||||
@@ -226,7 +231,8 @@ export class DiffEditorWidget extends Disposable implements editorBrowser.IDiffE
|
||||
|
||||
constructor(
|
||||
domElement: HTMLElement,
|
||||
options: editorBrowser.IDiffEditorConstructionOptions,
|
||||
options: Readonly<editorBrowser.IDiffEditorConstructionOptions>,
|
||||
codeEditorWidgetOptions: IDiffCodeEditorWidgetOptions,
|
||||
@IClipboardService clipboardService: IClipboardService,
|
||||
@IEditorWorkerService editorWorkerService: IEditorWorkerService,
|
||||
@IContextKeyService contextKeyService: IContextKeyService,
|
||||
@@ -287,6 +293,11 @@ export class DiffEditorWidget extends Disposable implements editorBrowser.IDiffE
|
||||
this._contextKeyService.createKey('isInEmbeddedDiffEditor', false);
|
||||
}
|
||||
|
||||
this._renderOverviewRuler = true;
|
||||
if (typeof options.renderOverviewRuler !== 'undefined') {
|
||||
this._renderOverviewRuler = Boolean(options.renderOverviewRuler);
|
||||
}
|
||||
|
||||
this._updateDecorationsRunner = this._register(new RunOnceScheduler(() => this._updateDecorations(), 0));
|
||||
|
||||
this._containerDomElement = document.createElement('div');
|
||||
@@ -308,7 +319,9 @@ export class DiffEditorWidget extends Disposable implements editorBrowser.IDiffE
|
||||
this._register(dom.addStandardDisposableListener(this._overviewDomElement, 'mousedown', (e) => {
|
||||
this._modifiedEditor.delegateVerticalScrollbarMouseDown(e);
|
||||
}));
|
||||
this._containerDomElement.appendChild(this._overviewDomElement);
|
||||
if (this._renderOverviewRuler) {
|
||||
this._containerDomElement.appendChild(this._overviewDomElement);
|
||||
}
|
||||
|
||||
// Create left side
|
||||
this._originalDomNode = document.createElement('div');
|
||||
@@ -334,7 +347,7 @@ export class DiffEditorWidget extends Disposable implements editorBrowser.IDiffE
|
||||
this._isVisible = true;
|
||||
this._isHandlingScrollEvent = false;
|
||||
|
||||
this._elementSizeObserver = this._register(new ElementSizeObserver(this._containerDomElement, undefined, () => this._onDidContainerSizeChanged()));
|
||||
this._elementSizeObserver = this._register(new ElementSizeObserver(this._containerDomElement, options.dimension, () => this._onDidContainerSizeChanged()));
|
||||
if (options.automaticLayout) {
|
||||
this._elementSizeObserver.startObserving();
|
||||
}
|
||||
@@ -353,8 +366,8 @@ export class DiffEditorWidget extends Disposable implements editorBrowser.IDiffE
|
||||
rightServices.set(IContextKeyService, rightContextKeyService);
|
||||
const rightScopedInstantiationService = instantiationService.createChild(rightServices);
|
||||
|
||||
this._originalEditor = this._createLeftHandSideEditor(options, leftScopedInstantiationService, leftContextKeyService);
|
||||
this._modifiedEditor = this._createRightHandSideEditor(options, rightScopedInstantiationService, rightContextKeyService);
|
||||
this._originalEditor = this._createLeftHandSideEditor(options, codeEditorWidgetOptions.originalEditor || {}, leftScopedInstantiationService, leftContextKeyService);
|
||||
this._modifiedEditor = this._createRightHandSideEditor(options, codeEditorWidgetOptions.modifiedEditor || {}, rightScopedInstantiationService, rightContextKeyService);
|
||||
|
||||
this._originalOverviewRuler = null;
|
||||
this._modifiedOverviewRuler = null;
|
||||
@@ -415,6 +428,10 @@ export class DiffEditorWidget extends Disposable implements editorBrowser.IDiffE
|
||||
return this._modifiedEditor.getContentHeight();
|
||||
}
|
||||
|
||||
public getViewWidth(): number {
|
||||
return this._elementSizeObserver.getWidth();
|
||||
}
|
||||
|
||||
private _setState(newState: editorBrowser.DiffEditorState): void {
|
||||
if (this._state === newState) {
|
||||
return;
|
||||
@@ -453,6 +470,10 @@ export class DiffEditorWidget extends Disposable implements editorBrowser.IDiffE
|
||||
}
|
||||
|
||||
private _recreateOverviewRulers(): void {
|
||||
if (!this._renderOverviewRuler) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (this._originalOverviewRuler) {
|
||||
this._overviewDomElement.removeChild(this._originalOverviewRuler.getDomNode());
|
||||
this._originalOverviewRuler.dispose();
|
||||
@@ -474,8 +495,8 @@ export class DiffEditorWidget extends Disposable implements editorBrowser.IDiffE
|
||||
this._layoutOverviewRulers();
|
||||
}
|
||||
|
||||
private _createLeftHandSideEditor(options: editorBrowser.IDiffEditorConstructionOptions, instantiationService: IInstantiationService, contextKeyService: IContextKeyService): CodeEditorWidget {
|
||||
const editor = this._createInnerEditor(instantiationService, this._originalDomNode, this._adjustOptionsForLeftHandSide(options));
|
||||
private _createLeftHandSideEditor(options: Readonly<editorBrowser.IDiffEditorConstructionOptions>, codeEditorWidgetOptions: ICodeEditorWidgetOptions, instantiationService: IInstantiationService, contextKeyService: IContextKeyService): CodeEditorWidget {
|
||||
const editor = this._createInnerEditor(instantiationService, this._originalDomNode, this._adjustOptionsForLeftHandSide(options), codeEditorWidgetOptions);
|
||||
|
||||
this._register(editor.onDidScrollChange((e) => {
|
||||
if (this._isHandlingScrollEvent) {
|
||||
@@ -536,8 +557,8 @@ export class DiffEditorWidget extends Disposable implements editorBrowser.IDiffE
|
||||
return editor;
|
||||
}
|
||||
|
||||
private _createRightHandSideEditor(options: editorBrowser.IDiffEditorConstructionOptions, instantiationService: IInstantiationService, contextKeyService: IContextKeyService): CodeEditorWidget {
|
||||
const editor = this._createInnerEditor(instantiationService, this._modifiedDomNode, this._adjustOptionsForRightHandSide(options));
|
||||
private _createRightHandSideEditor(options: Readonly<editorBrowser.IDiffEditorConstructionOptions>, codeEditorWidgetOptions: ICodeEditorWidgetOptions, instantiationService: IInstantiationService, contextKeyService: IContextKeyService): CodeEditorWidget {
|
||||
const editor = this._createInnerEditor(instantiationService, this._modifiedDomNode, this._adjustOptionsForRightHandSide(options), codeEditorWidgetOptions);
|
||||
|
||||
this._register(editor.onDidScrollChange((e) => {
|
||||
if (this._isHandlingScrollEvent) {
|
||||
@@ -604,8 +625,8 @@ export class DiffEditorWidget extends Disposable implements editorBrowser.IDiffE
|
||||
return editor;
|
||||
}
|
||||
|
||||
protected _createInnerEditor(instantiationService: IInstantiationService, container: HTMLElement, options: IEditorOptions): CodeEditorWidget {
|
||||
return instantiationService.createInstance(CodeEditorWidget, container, options, {});
|
||||
protected _createInnerEditor(instantiationService: IInstantiationService, container: HTMLElement, options: Readonly<editorBrowser.IEditorConstructionOptions>, editorWidgetOptions: ICodeEditorWidgetOptions): CodeEditorWidget {
|
||||
return instantiationService.createInstance(CodeEditorWidget, container, options, editorWidgetOptions);
|
||||
}
|
||||
|
||||
public dispose(): void {
|
||||
@@ -627,7 +648,9 @@ export class DiffEditorWidget extends Disposable implements editorBrowser.IDiffE
|
||||
this._modifiedOverviewRuler.dispose();
|
||||
}
|
||||
this._overviewDomElement.removeChild(this._overviewViewportDomElement.domNode);
|
||||
this._containerDomElement.removeChild(this._overviewDomElement);
|
||||
if (this._renderOverviewRuler) {
|
||||
this._containerDomElement.removeChild(this._overviewDomElement);
|
||||
}
|
||||
|
||||
this._containerDomElement.removeChild(this._originalDomNode);
|
||||
this._originalEditor.dispose();
|
||||
@@ -678,7 +701,7 @@ export class DiffEditorWidget extends Disposable implements editorBrowser.IDiffE
|
||||
return this._modifiedEditor;
|
||||
}
|
||||
|
||||
public updateOptions(newOptions: IDiffEditorOptions): void {
|
||||
public updateOptions(newOptions: Readonly<IDiffEditorOptions>): void {
|
||||
|
||||
// Handle side by side
|
||||
let renderSideBySideChanged = false;
|
||||
@@ -740,6 +763,16 @@ export class DiffEditorWidget extends Disposable implements editorBrowser.IDiffE
|
||||
// Update class name
|
||||
this._containerDomElement.className = DiffEditorWidget._getClassName(this._themeService.getColorTheme(), this._renderSideBySide);
|
||||
}
|
||||
|
||||
// renderOverviewRuler
|
||||
if (typeof newOptions.renderOverviewRuler !== 'undefined' && this._renderOverviewRuler !== newOptions.renderOverviewRuler) {
|
||||
this._renderOverviewRuler = newOptions.renderOverviewRuler;
|
||||
if (this._renderOverviewRuler) {
|
||||
this._containerDomElement.appendChild(this._overviewDomElement);
|
||||
} else {
|
||||
this._containerDomElement.removeChild(this._overviewDomElement);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public getModel(): editorCommon.IDiffEditorModel {
|
||||
@@ -749,7 +782,7 @@ export class DiffEditorWidget extends Disposable implements editorBrowser.IDiffE
|
||||
};
|
||||
}
|
||||
|
||||
public setModel(model: editorCommon.IDiffEditorModel): void {
|
||||
public setModel(model: editorCommon.IDiffEditorModel | null): void {
|
||||
// Guard us against partial null model
|
||||
if (model && (!model.original || !model.modified)) {
|
||||
throw new Error(!model.original ? 'DiffEditorWidget.setModel: Original model is null' : 'DiffEditorWidget.setModel: Modified model is null');
|
||||
@@ -911,7 +944,7 @@ export class DiffEditorWidget extends Disposable implements editorBrowser.IDiffE
|
||||
}
|
||||
|
||||
public restoreViewState(s: editorCommon.IDiffEditorViewState): void {
|
||||
if (s.original && s.modified) {
|
||||
if (s && s.original && s.modified) {
|
||||
const diffEditorState = <editorCommon.IDiffEditorViewState>s;
|
||||
this._originalEditor.restoreViewState(diffEditorState.original);
|
||||
this._modifiedEditor.restoreViewState(diffEditorState.modified);
|
||||
@@ -969,6 +1002,10 @@ export class DiffEditorWidget extends Disposable implements editorBrowser.IDiffE
|
||||
}
|
||||
|
||||
private _layoutOverviewRulers(): void {
|
||||
if (!this._renderOverviewRuler) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!this._originalOverviewRuler || !this._modifiedOverviewRuler) {
|
||||
return;
|
||||
}
|
||||
@@ -1079,9 +1116,10 @@ export class DiffEditorWidget extends Disposable implements editorBrowser.IDiffE
|
||||
}
|
||||
|
||||
private _updateDecorations(): void {
|
||||
if (!this._originalEditor.getModel() || !this._modifiedEditor.getModel() || !this._originalOverviewRuler || !this._modifiedOverviewRuler) {
|
||||
if (!this._originalEditor.getModel() || !this._modifiedEditor.getModel()) {
|
||||
return;
|
||||
}
|
||||
|
||||
const lineChanges = (this._diffComputationResult ? this._diffComputationResult.changes : []);
|
||||
|
||||
const foreignOriginal = this._originalEditorState.getForeignViewZones(this._originalEditor.getWhitespaces());
|
||||
@@ -1098,25 +1136,24 @@ export class DiffEditorWidget extends Disposable implements editorBrowser.IDiffE
|
||||
}
|
||||
}
|
||||
|
||||
private _adjustOptionsForSubEditor(options: editorBrowser.IDiffEditorConstructionOptions): editorBrowser.IDiffEditorConstructionOptions {
|
||||
const clonedOptions: editorBrowser.IDiffEditorConstructionOptions = objects.deepClone(options || {});
|
||||
private _adjustOptionsForSubEditor(options: Readonly<editorBrowser.IDiffEditorConstructionOptions>): editorBrowser.IEditorConstructionOptions {
|
||||
const clonedOptions = { ...options };
|
||||
clonedOptions.inDiffEditor = true;
|
||||
clonedOptions.automaticLayout = false;
|
||||
clonedOptions.scrollbar = clonedOptions.scrollbar || {};
|
||||
// Clone scrollbar options before changing them
|
||||
clonedOptions.scrollbar = { ...(clonedOptions.scrollbar || {}) };
|
||||
clonedOptions.scrollbar.vertical = 'visible';
|
||||
clonedOptions.folding = false;
|
||||
clonedOptions.codeLens = this._diffCodeLens;
|
||||
clonedOptions.fixedOverflowWidgets = true;
|
||||
clonedOptions.overflowWidgetsDomNode = options.overflowWidgetsDomNode;
|
||||
// clonedOptions.lineDecorationsWidth = '2ch';
|
||||
if (!clonedOptions.minimap) {
|
||||
clonedOptions.minimap = {};
|
||||
}
|
||||
// Clone minimap options before changing them
|
||||
clonedOptions.minimap = { ...(clonedOptions.minimap || {}) };
|
||||
clonedOptions.minimap.enabled = false;
|
||||
return clonedOptions;
|
||||
}
|
||||
|
||||
private _adjustOptionsForLeftHandSide(options: editorBrowser.IDiffEditorConstructionOptions): editorBrowser.IEditorConstructionOptions {
|
||||
private _adjustOptionsForLeftHandSide(options: Readonly<editorBrowser.IDiffEditorConstructionOptions>): editorBrowser.IEditorConstructionOptions {
|
||||
const result = this._adjustOptionsForSubEditor(options);
|
||||
if (!this._renderSideBySide) {
|
||||
// never wrap hidden editor
|
||||
@@ -1126,16 +1163,28 @@ export class DiffEditorWidget extends Disposable implements editorBrowser.IDiffE
|
||||
}
|
||||
result.readOnly = !this._originalIsEditable;
|
||||
result.extraEditorClassName = 'original-in-monaco-diff-editor';
|
||||
return result;
|
||||
return {
|
||||
...result,
|
||||
dimension: {
|
||||
height: 0,
|
||||
width: 0
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
private _adjustOptionsForRightHandSide(options: editorBrowser.IDiffEditorConstructionOptions): editorBrowser.IEditorConstructionOptions {
|
||||
private _adjustOptionsForRightHandSide(options: Readonly<editorBrowser.IDiffEditorConstructionOptions>): editorBrowser.IEditorConstructionOptions {
|
||||
const result = this._adjustOptionsForSubEditor(options);
|
||||
result.wordWrapOverride1 = this._diffWordWrap;
|
||||
result.revealHorizontalRightPadding = EditorOptions.revealHorizontalRightPadding.defaultValue + DiffEditorWidget.ENTIRE_DIFF_OVERVIEW_WIDTH;
|
||||
result.scrollbar!.verticalHasArrows = false;
|
||||
result.extraEditorClassName = 'modified-in-monaco-diff-editor';
|
||||
return result;
|
||||
return {
|
||||
...result,
|
||||
dimension: {
|
||||
height: 0,
|
||||
width: 0
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
public doLayout(): void {
|
||||
@@ -1164,7 +1213,7 @@ export class DiffEditorWidget extends Disposable implements editorBrowser.IDiffE
|
||||
this._overviewViewportDomElement.setHeight(30);
|
||||
|
||||
this._originalEditor.layout({ width: splitPoint, height: (height - reviewHeight) });
|
||||
this._modifiedEditor.layout({ width: width - splitPoint - DiffEditorWidget.ENTIRE_DIFF_OVERVIEW_WIDTH, height: (height - reviewHeight) });
|
||||
this._modifiedEditor.layout({ width: width - splitPoint - (this._renderOverviewRuler ? DiffEditorWidget.ENTIRE_DIFF_OVERVIEW_WIDTH : 0), height: (height - reviewHeight) });
|
||||
|
||||
if (this._originalOverviewRuler || this._modifiedOverviewRuler) {
|
||||
this._layoutOverviewRulers();
|
||||
@@ -1218,6 +1267,12 @@ export class DiffEditorWidget extends Disposable implements editorBrowser.IDiffE
|
||||
return (this._elementSizeObserver.getHeight() - this._getReviewHeight());
|
||||
},
|
||||
|
||||
getOptions: () => {
|
||||
return {
|
||||
renderOverviewRuler: this._renderOverviewRuler
|
||||
};
|
||||
},
|
||||
|
||||
getContainerDomNode: () => {
|
||||
return this._containerDomElement;
|
||||
},
|
||||
@@ -1347,6 +1402,7 @@ export class DiffEditorWidget extends Disposable implements editorBrowser.IDiffE
|
||||
interface IDataSource {
|
||||
getWidth(): number;
|
||||
getHeight(): number;
|
||||
getOptions(): { renderOverviewRuler: boolean; };
|
||||
getContainerDomNode(): HTMLElement;
|
||||
relayoutEditors(): void;
|
||||
|
||||
@@ -1806,7 +1862,7 @@ class DiffEditorWidgetSideBySide extends DiffEditorWidgetStyle implements IVerti
|
||||
|
||||
public layout(sashRatio: number | null = this._sashRatio): number {
|
||||
const w = this._dataSource.getWidth();
|
||||
const contentWidth = w - DiffEditorWidget.ENTIRE_DIFF_OVERVIEW_WIDTH;
|
||||
const contentWidth = w - (this._dataSource.getOptions().renderOverviewRuler ? DiffEditorWidget.ENTIRE_DIFF_OVERVIEW_WIDTH : 0);
|
||||
|
||||
let sashPosition = Math.floor((sashRatio || 0.5) * contentWidth);
|
||||
const midPoint = Math.floor(0.5 * contentWidth);
|
||||
@@ -1839,7 +1895,7 @@ class DiffEditorWidgetSideBySide extends DiffEditorWidgetStyle implements IVerti
|
||||
|
||||
private _onSashDrag(e: ISashEvent): void {
|
||||
const w = this._dataSource.getWidth();
|
||||
const contentWidth = w - DiffEditorWidget.ENTIRE_DIFF_OVERVIEW_WIDTH;
|
||||
const contentWidth = w - (this._dataSource.getOptions().renderOverviewRuler ? DiffEditorWidget.ENTIRE_DIFF_OVERVIEW_WIDTH : 0);
|
||||
const sashPosition = this.layout((this._startSashPosition! + (e.currentX - e.startX)) / contentWidth);
|
||||
|
||||
this._sashRatio = sashPosition / contentWidth;
|
||||
@@ -2370,7 +2426,7 @@ class InlineViewZonesComputer extends ViewZonesComputer {
|
||||
|
||||
const html = sb.build();
|
||||
const trustedhtml = ttPolicy ? ttPolicy.createHTML(html) : html;
|
||||
domNode.innerHTML = trustedhtml as unknown as string;
|
||||
domNode.innerHTML = trustedhtml as string;
|
||||
viewZone.minWidthInPx = (maxCharsPerLine * typicalHalfwidthCharacterWidth);
|
||||
|
||||
if (viewLineCounts) {
|
||||
|
||||
@@ -80,6 +80,8 @@ const diffReviewCloseIcon = registerIcon('diff-review-close', Codicon.close, nls
|
||||
|
||||
export class DiffReview extends Disposable {
|
||||
|
||||
private static _ttPolicy = window.trustedTypes?.createPolicy('diffReview', { createHTML: value => value });
|
||||
|
||||
private readonly _diffEditor: DiffEditorWidget;
|
||||
private _isVisible: boolean;
|
||||
public readonly shadow: FastDomNode<HTMLElement>;
|
||||
@@ -734,14 +736,18 @@ export class DiffReview extends Disposable {
|
||||
|
||||
let lineContent: string;
|
||||
if (modifiedLine !== 0) {
|
||||
cell.insertAdjacentHTML('beforeend',
|
||||
this._renderLine(modifiedModel, modifiedOptions, modifiedModelOpts.tabSize, modifiedLine)
|
||||
);
|
||||
let html: string | TrustedHTML = this._renderLine(modifiedModel, modifiedOptions, modifiedModelOpts.tabSize, modifiedLine);
|
||||
if (DiffReview._ttPolicy) {
|
||||
html = DiffReview._ttPolicy.createHTML(html as string);
|
||||
}
|
||||
cell.insertAdjacentHTML('beforeend', html as string);
|
||||
lineContent = modifiedModel.getLineContent(modifiedLine);
|
||||
} else {
|
||||
cell.insertAdjacentHTML('beforeend',
|
||||
this._renderLine(originalModel, originalOptions, originalModelOpts.tabSize, originalLine)
|
||||
);
|
||||
let html: string | TrustedHTML = this._renderLine(originalModel, originalOptions, originalModelOpts.tabSize, originalLine);
|
||||
if (DiffReview._ttPolicy) {
|
||||
html = DiffReview._ttPolicy.createHTML(html as string);
|
||||
}
|
||||
cell.insertAdjacentHTML('beforeend', html as string);
|
||||
lineContent = originalModel.getLineContent(originalLine);
|
||||
}
|
||||
|
||||
|
||||
@@ -82,7 +82,7 @@ export class EmbeddedDiffEditorWidget extends DiffEditorWidget {
|
||||
@IClipboardService clipboardService: IClipboardService,
|
||||
@IEditorProgressService editorProgressService: IEditorProgressService,
|
||||
) {
|
||||
super(domElement, parentEditor.getRawOptions(), clipboardService, editorWorkerService, contextKeyService, instantiationService, codeEditorService, themeService, notificationService, contextMenuService, editorProgressService);
|
||||
super(domElement, parentEditor.getRawOptions(), {}, clipboardService, editorWorkerService, contextKeyService, instantiationService, codeEditorService, themeService, notificationService, contextMenuService, editorProgressService);
|
||||
|
||||
this._parentEditor = parentEditor;
|
||||
this._overwriteOptions = options;
|
||||
|
||||
@@ -272,7 +272,7 @@ function migrateOptions(options: IEditorOptions): void {
|
||||
}
|
||||
}
|
||||
|
||||
function deepCloneAndMigrateOptions(_options: IEditorOptions): IEditorOptions {
|
||||
function deepCloneAndMigrateOptions(_options: Readonly<IEditorOptions>): IEditorOptions {
|
||||
const options = objects.deepClone(_options);
|
||||
migrateOptions(options);
|
||||
return options;
|
||||
@@ -298,7 +298,7 @@ export abstract class CommonEditorConfiguration extends Disposable implements IC
|
||||
private _readOptions: RawEditorOptions;
|
||||
protected _validatedOptions: ValidatedEditorOptions;
|
||||
|
||||
constructor(isSimpleWidget: boolean, _options: IEditorOptions) {
|
||||
constructor(isSimpleWidget: boolean, _options: Readonly<IEditorOptions>) {
|
||||
super();
|
||||
this.isSimpleWidget = isSimpleWidget;
|
||||
|
||||
@@ -318,8 +318,7 @@ export abstract class CommonEditorConfiguration extends Disposable implements IC
|
||||
public observeReferenceElement(dimension?: IDimension): void {
|
||||
}
|
||||
|
||||
public dispose(): void {
|
||||
super.dispose();
|
||||
public updatePixelRatio(): void {
|
||||
}
|
||||
|
||||
protected _recomputeOptions(): void {
|
||||
@@ -348,7 +347,7 @@ export abstract class CommonEditorConfiguration extends Disposable implements IC
|
||||
|
||||
private _computeInternalOptions(): ComputedEditorOptions {
|
||||
const partialEnv = this._getEnvConfiguration();
|
||||
const bareFontInfo = BareFontInfo.createFromValidatedSettings(this._validatedOptions, partialEnv.zoomLevel, this.isSimpleWidget);
|
||||
const bareFontInfo = BareFontInfo.createFromValidatedSettings(this._validatedOptions, partialEnv.zoomLevel, partialEnv.pixelRatio, this.isSimpleWidget);
|
||||
const env: IEnvironmentalOptions = {
|
||||
memory: this._computeOptionsMemory,
|
||||
outerWidth: partialEnv.outerWidth,
|
||||
@@ -394,7 +393,7 @@ export abstract class CommonEditorConfiguration extends Disposable implements IC
|
||||
return true;
|
||||
}
|
||||
|
||||
public updateOptions(_newOptions: IEditorOptions): void {
|
||||
public updateOptions(_newOptions: Readonly<IEditorOptions>): void {
|
||||
if (typeof _newOptions === 'undefined') {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -625,6 +625,10 @@ export interface IEditorOptions {
|
||||
* Controls strikethrough deprecated variables.
|
||||
*/
|
||||
showDeprecated?: boolean;
|
||||
/**
|
||||
* Control the behavior and rendering of the inline hints.
|
||||
*/
|
||||
inlineHints?: IEditorInlineHintsOptions;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -677,6 +681,11 @@ export interface IDiffEditorOptions extends IEditorOptions {
|
||||
* Defaults to false
|
||||
*/
|
||||
isInEmbeddedEditor?: boolean;
|
||||
/**
|
||||
* Is the diff editor should render overview ruler
|
||||
* Defaults to true
|
||||
*/
|
||||
renderOverviewRuler?: boolean;
|
||||
/**
|
||||
* Control the wrapping of the diff editor.
|
||||
*/
|
||||
@@ -2364,6 +2373,74 @@ class EditorLightbulb extends BaseEditorOption<EditorOption.lightbulb, EditorLig
|
||||
|
||||
//#endregion
|
||||
|
||||
//#region inlineHints
|
||||
|
||||
/**
|
||||
* Configuration options for editor inlineHints
|
||||
*/
|
||||
export interface IEditorInlineHintsOptions {
|
||||
/**
|
||||
* Enable the inline hints.
|
||||
* Defaults to true.
|
||||
*/
|
||||
enabled?: boolean;
|
||||
|
||||
/**
|
||||
* Font size of inline hints.
|
||||
* Default to 90% of the editor font size.
|
||||
*/
|
||||
fontSize?: number;
|
||||
|
||||
/**
|
||||
* Font family of inline hints.
|
||||
* Defaults to editor font family.
|
||||
*/
|
||||
fontFamily?: string;
|
||||
}
|
||||
|
||||
export type EditorInlineHintsOptions = Readonly<Required<IEditorInlineHintsOptions>>;
|
||||
|
||||
class EditorInlineHints extends BaseEditorOption<EditorOption.inlineHints, EditorInlineHintsOptions> {
|
||||
|
||||
constructor() {
|
||||
const defaults: EditorInlineHintsOptions = { enabled: true, fontSize: 0, fontFamily: EDITOR_FONT_DEFAULTS.fontFamily };
|
||||
super(
|
||||
EditorOption.inlineHints, 'inlineHints', defaults,
|
||||
{
|
||||
'editor.inlineHints.enabled': {
|
||||
type: 'boolean',
|
||||
default: defaults.enabled,
|
||||
description: nls.localize('inlineHints.enable', "Enables the inline hints in the editor.")
|
||||
},
|
||||
'editor.inlineHints.fontSize': {
|
||||
type: 'number',
|
||||
default: defaults.fontSize,
|
||||
description: nls.localize('inlineHints.fontSize', "Controls font size of inline hints in the editor. When set to `0`, the 90% of `#editor.fontSize#` is used.")
|
||||
},
|
||||
'editor.inlineHints.fontFamily': {
|
||||
type: 'string',
|
||||
default: defaults.fontFamily,
|
||||
description: nls.localize('inlineHints.fontFamily', "Controls font family of inline hints in the editor.")
|
||||
},
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
public validate(_input: any): EditorInlineHintsOptions {
|
||||
if (!_input || typeof _input !== 'object') {
|
||||
return this.defaultValue;
|
||||
}
|
||||
const input = _input as IEditorInlineHintsOptions;
|
||||
return {
|
||||
enabled: boolean(input.enabled, this.defaultValue.enabled),
|
||||
fontSize: EditorIntOption.clampedInt(input.fontSize, this.defaultValue.fontSize, 0, 100),
|
||||
fontFamily: EditorStringOption.string(input.fontFamily, this.defaultValue.fontFamily)
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
//#endregion
|
||||
|
||||
//#region lineHeight
|
||||
|
||||
class EditorLineHeight extends EditorIntOption<EditorOption.lineHeight> {
|
||||
@@ -3273,7 +3350,7 @@ class EditorSuggest extends BaseEditorOption<EditorOption.suggest, InternalSugge
|
||||
'editor.suggest.showInlineDetails': {
|
||||
type: 'boolean',
|
||||
default: defaults.showInlineDetails,
|
||||
description: nls.localize('suggest.showInlineDetails', "Controls whether sugget details show inline with the label or only in the details widget")
|
||||
description: nls.localize('suggest.showInlineDetails', "Controls whether suggest details show inline with the label or only in the details widget")
|
||||
},
|
||||
'editor.suggest.maxVisibleSuggestions': {
|
||||
type: 'number',
|
||||
@@ -3754,7 +3831,7 @@ export const enum EditorOption {
|
||||
wrappingIndent,
|
||||
wrappingStrategy,
|
||||
showDeprecated,
|
||||
|
||||
inlineHints,
|
||||
// Leave these at the end (because they have dependencies!)
|
||||
editorClassName,
|
||||
pixelRatio,
|
||||
@@ -4258,6 +4335,7 @@ export const EditorOptions = {
|
||||
EditorOption.showDeprecated, 'showDeprecated', true,
|
||||
{ description: nls.localize('showDeprecated', "Controls strikethrough deprecated variables.") }
|
||||
)),
|
||||
inlineHints: register(new EditorInlineHints()),
|
||||
snippetSuggestions: register(new EditorStringEnumOption(
|
||||
EditorOption.snippetSuggestions, 'snippetSuggestions',
|
||||
'inline' as 'top' | 'bottom' | 'inline' | 'none',
|
||||
|
||||
@@ -24,33 +24,33 @@ export class BareFontInfo {
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
public static createFromValidatedSettings(options: ValidatedEditorOptions, zoomLevel: number, ignoreEditorZoom: boolean): BareFontInfo {
|
||||
public static createFromValidatedSettings(options: ValidatedEditorOptions, zoomLevel: number, pixelRatio: number, ignoreEditorZoom: boolean): BareFontInfo {
|
||||
const fontFamily = options.get(EditorOption.fontFamily);
|
||||
const fontWeight = options.get(EditorOption.fontWeight);
|
||||
const fontSize = options.get(EditorOption.fontSize);
|
||||
const fontFeatureSettings = options.get(EditorOption.fontLigatures);
|
||||
const lineHeight = options.get(EditorOption.lineHeight);
|
||||
const letterSpacing = options.get(EditorOption.letterSpacing);
|
||||
return BareFontInfo._create(fontFamily, fontWeight, fontSize, fontFeatureSettings, lineHeight, letterSpacing, zoomLevel, ignoreEditorZoom);
|
||||
return BareFontInfo._create(fontFamily, fontWeight, fontSize, fontFeatureSettings, lineHeight, letterSpacing, zoomLevel, pixelRatio, ignoreEditorZoom);
|
||||
}
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
public static createFromRawSettings(opts: { fontFamily?: string; fontWeight?: string; fontSize?: number; fontLigatures?: boolean | string; lineHeight?: number; letterSpacing?: number; }, zoomLevel: number, ignoreEditorZoom: boolean = false): BareFontInfo {
|
||||
public static createFromRawSettings(opts: { fontFamily?: string; fontWeight?: string; fontSize?: number; fontLigatures?: boolean | string; lineHeight?: number; letterSpacing?: number; }, zoomLevel: number, pixelRatio: number, ignoreEditorZoom: boolean = false): BareFontInfo {
|
||||
const fontFamily = EditorOptions.fontFamily.validate(opts.fontFamily);
|
||||
const fontWeight = EditorOptions.fontWeight.validate(opts.fontWeight);
|
||||
const fontSize = EditorOptions.fontSize.validate(opts.fontSize);
|
||||
const fontFeatureSettings = EditorOptions.fontLigatures2.validate(opts.fontLigatures);
|
||||
const lineHeight = EditorOptions.lineHeight.validate(opts.lineHeight);
|
||||
const letterSpacing = EditorOptions.letterSpacing.validate(opts.letterSpacing);
|
||||
return BareFontInfo._create(fontFamily, fontWeight, fontSize, fontFeatureSettings, lineHeight, letterSpacing, zoomLevel, ignoreEditorZoom);
|
||||
return BareFontInfo._create(fontFamily, fontWeight, fontSize, fontFeatureSettings, lineHeight, letterSpacing, zoomLevel, pixelRatio, ignoreEditorZoom);
|
||||
}
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
private static _create(fontFamily: string, fontWeight: string, fontSize: number, fontFeatureSettings: string, lineHeight: number, letterSpacing: number, zoomLevel: number, ignoreEditorZoom: boolean): BareFontInfo {
|
||||
private static _create(fontFamily: string, fontWeight: string, fontSize: number, fontFeatureSettings: string, lineHeight: number, letterSpacing: number, zoomLevel: number, pixelRatio: number, ignoreEditorZoom: boolean): BareFontInfo {
|
||||
if (lineHeight === 0) {
|
||||
lineHeight = Math.round(GOLDEN_LINE_HEIGHT_RATIO * fontSize);
|
||||
} else if (lineHeight < MINIMUM_LINE_HEIGHT) {
|
||||
@@ -63,6 +63,7 @@ export class BareFontInfo {
|
||||
|
||||
return new BareFontInfo({
|
||||
zoomLevel: zoomLevel,
|
||||
pixelRatio: pixelRatio,
|
||||
fontFamily: fontFamily,
|
||||
fontWeight: fontWeight,
|
||||
fontSize: fontSize,
|
||||
@@ -73,6 +74,7 @@ export class BareFontInfo {
|
||||
}
|
||||
|
||||
readonly zoomLevel: number;
|
||||
readonly pixelRatio: number;
|
||||
readonly fontFamily: string;
|
||||
readonly fontWeight: string;
|
||||
readonly fontSize: number;
|
||||
@@ -85,6 +87,7 @@ export class BareFontInfo {
|
||||
*/
|
||||
protected constructor(opts: {
|
||||
zoomLevel: number;
|
||||
pixelRatio: number;
|
||||
fontFamily: string;
|
||||
fontWeight: string;
|
||||
fontSize: number;
|
||||
@@ -93,6 +96,7 @@ export class BareFontInfo {
|
||||
letterSpacing: number;
|
||||
}) {
|
||||
this.zoomLevel = opts.zoomLevel;
|
||||
this.pixelRatio = opts.pixelRatio;
|
||||
this.fontFamily = String(opts.fontFamily);
|
||||
this.fontWeight = String(opts.fontWeight);
|
||||
this.fontSize = opts.fontSize;
|
||||
@@ -105,7 +109,7 @@ export class BareFontInfo {
|
||||
* @internal
|
||||
*/
|
||||
public getId(): string {
|
||||
return this.zoomLevel + '-' + this.fontFamily + '-' + this.fontWeight + '-' + this.fontSize + '-' + this.fontFeatureSettings + '-' + this.lineHeight + '-' + this.letterSpacing;
|
||||
return this.zoomLevel + '-' + this.pixelRatio + '-' + this.fontFamily + '-' + this.fontWeight + '-' + this.fontSize + '-' + this.fontFeatureSettings + '-' + this.lineHeight + '-' + this.letterSpacing;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -125,9 +129,13 @@ export class BareFontInfo {
|
||||
}
|
||||
}
|
||||
|
||||
// change this whenever `FontInfo` members are changed
|
||||
export const SERIALIZED_FONT_INFO_VERSION = 1;
|
||||
|
||||
export class FontInfo extends BareFontInfo {
|
||||
readonly _editorStylingBrand: void;
|
||||
|
||||
readonly version: number = SERIALIZED_FONT_INFO_VERSION;
|
||||
readonly isTrusted: boolean;
|
||||
readonly isMonospace: boolean;
|
||||
readonly typicalHalfwidthCharacterWidth: number;
|
||||
@@ -143,6 +151,7 @@ export class FontInfo extends BareFontInfo {
|
||||
*/
|
||||
constructor(opts: {
|
||||
zoomLevel: number;
|
||||
pixelRatio: number;
|
||||
fontFamily: string;
|
||||
fontWeight: string;
|
||||
fontSize: number;
|
||||
|
||||
@@ -393,8 +393,8 @@ export class Cursor extends Disposable {
|
||||
return this._cursors.getPrimaryCursor().modelState.position;
|
||||
}
|
||||
|
||||
public setSelections(eventsCollector: ViewModelEventsCollector, source: string | null | undefined, selections: readonly ISelection[]): void {
|
||||
this.setStates(eventsCollector, source, CursorChangeReason.NotSet, CursorState.fromModelSelections(selections));
|
||||
public setSelections(eventsCollector: ViewModelEventsCollector, source: string | null | undefined, selections: readonly ISelection[], reason: CursorChangeReason): void {
|
||||
this.setStates(eventsCollector, source, reason, CursorState.fromModelSelections(selections));
|
||||
}
|
||||
|
||||
public getPrevEditOperationType(): EditOperationType {
|
||||
@@ -584,7 +584,7 @@ export class Cursor extends Disposable {
|
||||
});
|
||||
if (selections) {
|
||||
this._isHandling = false;
|
||||
this.setSelections(eventsCollector, source, selections);
|
||||
this.setSelections(eventsCollector, source, selections, CursorChangeReason.NotSet);
|
||||
}
|
||||
if (autoClosedCharactersRanges.length > 0) {
|
||||
this._pushAutoClosedAction(autoClosedCharactersRanges, autoClosedEnclosingRanges);
|
||||
|
||||
@@ -39,11 +39,11 @@ export class MoveOperations {
|
||||
public static leftPositionAtomicSoftTabs(model: ICursorSimpleModel, lineNumber: number, column: number, tabSize: number): Position {
|
||||
const minColumn = model.getLineMinColumn(lineNumber);
|
||||
const lineContent = model.getLineContent(lineNumber);
|
||||
const newPosition = AtomicTabMoveOperations.atomicPosition(lineContent, column - minColumn, tabSize, Direction.Left);
|
||||
if (newPosition === -1) {
|
||||
const newPosition = AtomicTabMoveOperations.atomicPosition(lineContent, column - 1, tabSize, Direction.Left);
|
||||
if (newPosition === -1 || newPosition + 1 < minColumn) {
|
||||
return this.leftPosition(model, lineNumber, column);
|
||||
}
|
||||
return new Position(lineNumber, minColumn + newPosition);
|
||||
return new Position(lineNumber, newPosition + 1);
|
||||
}
|
||||
|
||||
public static left(config: CursorConfiguration, model: ICursorSimpleModel, lineNumber: number, column: number): CursorPosition {
|
||||
@@ -81,13 +81,12 @@ export class MoveOperations {
|
||||
}
|
||||
|
||||
public static rightPositionAtomicSoftTabs(model: ICursorSimpleModel, lineNumber: number, column: number, tabSize: number, indentSize: number): Position {
|
||||
const minColumn = model.getLineMinColumn(lineNumber);
|
||||
const lineContent = model.getLineContent(lineNumber);
|
||||
const newPosition = AtomicTabMoveOperations.atomicPosition(lineContent, column - minColumn, tabSize, Direction.Right);
|
||||
const newPosition = AtomicTabMoveOperations.atomicPosition(lineContent, column - 1, tabSize, Direction.Right);
|
||||
if (newPosition === -1) {
|
||||
return this.rightPosition(model, lineNumber, column);
|
||||
}
|
||||
return new Position(lineNumber, minColumn + newPosition);
|
||||
return new Position(lineNumber, newPosition + 1);
|
||||
}
|
||||
|
||||
public static right(config: CursorConfiguration, model: ICursorSimpleModel, lineNumber: number, column: number): CursorPosition {
|
||||
|
||||
@@ -351,13 +351,6 @@ export class TypeOperations {
|
||||
if (ir) {
|
||||
let oldEndViewColumn = CursorColumns.visibleColumnFromColumn2(config, model, range.getEndPosition());
|
||||
const oldEndColumn = range.endColumn;
|
||||
|
||||
let beforeText = '\n';
|
||||
if (indentation !== config.normalizeIndentation(ir.beforeEnter)) {
|
||||
beforeText = config.normalizeIndentation(ir.beforeEnter) + lineText.substring(indentation.length, range.startColumn - 1) + '\n';
|
||||
range = new Range(range.startLineNumber, 1, range.endLineNumber, range.endColumn);
|
||||
}
|
||||
|
||||
const newLineContent = model.getLineContent(range.endLineNumber);
|
||||
const firstNonWhitespace = strings.firstNonWhitespaceIndex(newLineContent);
|
||||
if (firstNonWhitespace >= 0) {
|
||||
@@ -367,7 +360,7 @@ export class TypeOperations {
|
||||
}
|
||||
|
||||
if (keepPosition) {
|
||||
return new ReplaceCommandWithoutChangingPosition(range, beforeText + config.normalizeIndentation(ir.afterEnter), true);
|
||||
return new ReplaceCommandWithoutChangingPosition(range, '\n' + config.normalizeIndentation(ir.afterEnter), true);
|
||||
} else {
|
||||
let offset = 0;
|
||||
if (oldEndColumn <= firstNonWhitespace + 1) {
|
||||
@@ -376,7 +369,7 @@ export class TypeOperations {
|
||||
}
|
||||
offset = Math.min(oldEndViewColumn + 1 - config.normalizeIndentation(ir.afterEnter).length - 1, 0);
|
||||
}
|
||||
return new ReplaceCommandWithOffsetCursorState(range, beforeText + config.normalizeIndentation(ir.afterEnter), 0, offset, true);
|
||||
return new ReplaceCommandWithOffsetCursorState(range, '\n' + config.normalizeIndentation(ir.afterEnter), 0, offset, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -313,6 +313,13 @@ export class DiffComputer {
|
||||
|
||||
if (this.original.lines.length === 1 && this.original.lines[0].length === 0) {
|
||||
// empty original => fast path
|
||||
if (this.modified.lines.length === 1 && this.modified.lines[0].length === 0) {
|
||||
return {
|
||||
quitEarly: false,
|
||||
changes: []
|
||||
};
|
||||
}
|
||||
|
||||
return {
|
||||
quitEarly: false,
|
||||
changes: [{
|
||||
|
||||
@@ -157,9 +157,10 @@ export interface IConfiguration extends IDisposable {
|
||||
|
||||
setMaxLineNumber(maxLineNumber: number): void;
|
||||
setViewLineCount(viewLineCount: number): void;
|
||||
updateOptions(newOptions: IEditorOptions): void;
|
||||
updateOptions(newOptions: Readonly<IEditorOptions>): void;
|
||||
getRawOptions(): IEditorOptions;
|
||||
observeReferenceElement(dimension?: IDimension): void;
|
||||
updatePixelRatio(): void;
|
||||
setIsDominatedByLongLines(isDominatedByLongLines: boolean): void;
|
||||
}
|
||||
|
||||
@@ -605,6 +606,7 @@ export interface IThemeDecorationRenderOptions {
|
||||
|
||||
fontStyle?: string;
|
||||
fontWeight?: string;
|
||||
fontSize?: string;
|
||||
textDecoration?: string;
|
||||
cursor?: string;
|
||||
color?: string | ThemeColor;
|
||||
@@ -629,13 +631,17 @@ export interface IContentDecorationRenderOptions {
|
||||
|
||||
border?: string;
|
||||
borderColor?: string | ThemeColor;
|
||||
borderRadius?: string;
|
||||
fontStyle?: string;
|
||||
fontWeight?: string;
|
||||
fontSize?: string;
|
||||
fontFamily?: string;
|
||||
textDecoration?: string;
|
||||
color?: string | ThemeColor;
|
||||
backgroundColor?: string | ThemeColor;
|
||||
|
||||
margin?: string;
|
||||
padding?: string;
|
||||
width?: string;
|
||||
height?: string;
|
||||
}
|
||||
|
||||
@@ -61,6 +61,7 @@ export namespace EditorContextKeys {
|
||||
export const hasReferenceProvider = new RawContextKey<boolean>('editorHasReferenceProvider', false);
|
||||
export const hasRenameProvider = new RawContextKey<boolean>('editorHasRenameProvider', false);
|
||||
export const hasSignatureHelpProvider = new RawContextKey<boolean>('editorHasSignatureHelpProvider', false);
|
||||
export const hasInlineHintsProvider = new RawContextKey<boolean>('editorHasInlineHintsProvider', false);
|
||||
|
||||
// -- mode context keys: formatting
|
||||
export const hasDocumentFormattingProvider = new RawContextKey<boolean>('editorHasDocumentFormattingProvider', false);
|
||||
|
||||
@@ -600,12 +600,6 @@ export interface ITextModel {
|
||||
*/
|
||||
setValue(newValue: string): void;
|
||||
|
||||
/**
|
||||
* Replace the entire text buffer value contained in this model.
|
||||
* @internal
|
||||
*/
|
||||
setValueFromTextBuffer(newValue: ITextBuffer): void;
|
||||
|
||||
/**
|
||||
* Get the text stored in this model.
|
||||
* @param eol The end of line character preference. Defaults to `EndOfLinePreference.TextDefined`.
|
||||
@@ -1276,7 +1270,7 @@ export interface ITextBufferBuilder {
|
||||
* @internal
|
||||
*/
|
||||
export interface ITextBufferFactory {
|
||||
create(defaultEOL: DefaultEndOfLine): ITextBuffer;
|
||||
create(defaultEOL: DefaultEndOfLine): { textBuffer: ITextBuffer; disposable: IDisposable; };
|
||||
getFirstLineText(lengthLimit: number): string;
|
||||
}
|
||||
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { CharCode } from 'vs/base/common/charCode';
|
||||
import { IDisposable } from 'vs/base/common/lifecycle';
|
||||
import * as strings from 'vs/base/common/strings';
|
||||
import { DefaultEndOfLine, ITextBuffer, ITextBufferBuilder, ITextBufferFactory } from 'vs/editor/common/model';
|
||||
import { StringBuffer, createLineStarts, createLineStartsFast } from 'vs/editor/common/model/pieceTreeTextBuffer/pieceTreeBase';
|
||||
@@ -38,7 +39,7 @@ export class PieceTreeTextBufferFactory implements ITextBufferFactory {
|
||||
return '\n';
|
||||
}
|
||||
|
||||
public create(defaultEOL: DefaultEndOfLine): ITextBuffer {
|
||||
public create(defaultEOL: DefaultEndOfLine): { textBuffer: ITextBuffer; disposable: IDisposable; } {
|
||||
const eol = this._getEOL(defaultEOL);
|
||||
let chunks = this._chunks;
|
||||
|
||||
@@ -54,7 +55,8 @@ export class PieceTreeTextBufferFactory implements ITextBufferFactory {
|
||||
}
|
||||
}
|
||||
|
||||
return new PieceTreeTextBuffer(chunks, this._bom, eol, this._containsRTL, this._containsUnusualLineTerminators, this._isBasicASCII, this._normalizeEOL);
|
||||
const textBuffer = new PieceTreeTextBuffer(chunks, this._bom, eol, this._containsRTL, this._containsUnusualLineTerminators, this._isBasicASCII, this._normalizeEOL);
|
||||
return { textBuffer: textBuffer, disposable: textBuffer };
|
||||
}
|
||||
|
||||
public getFirstLineText(lengthLimit: number): string {
|
||||
|
||||
@@ -37,6 +37,7 @@ import { EditorTheme } from 'vs/editor/common/view/viewContext';
|
||||
import { IUndoRedoService, ResourceEditStackSnapshot } from 'vs/platform/undoRedo/common/undoRedo';
|
||||
import { TextChange } from 'vs/editor/common/model/textChange';
|
||||
import { Constants } from 'vs/base/common/uint';
|
||||
import { PieceTreeTextBuffer } from 'vs/editor/common/model/pieceTreeTextBuffer/pieceTreeTextBuffer';
|
||||
|
||||
function createTextBufferBuilder() {
|
||||
return new PieceTreeTextBufferBuilder();
|
||||
@@ -106,7 +107,7 @@ export function createTextBufferFactoryFromSnapshot(snapshot: model.ITextSnapsho
|
||||
return builder.finish();
|
||||
}
|
||||
|
||||
export function createTextBuffer(value: string | model.ITextBufferFactory, defaultEOL: model.DefaultEndOfLine): model.ITextBuffer {
|
||||
export function createTextBuffer(value: string | model.ITextBufferFactory, defaultEOL: model.DefaultEndOfLine): { textBuffer: model.ITextBuffer; disposable: IDisposable; } {
|
||||
const factory = (typeof value === 'string' ? createTextBufferFactory(value) : value);
|
||||
return factory.create(defaultEOL);
|
||||
}
|
||||
@@ -268,6 +269,7 @@ export class TextModel extends Disposable implements model.ITextModel {
|
||||
private readonly _undoRedoService: IUndoRedoService;
|
||||
private _attachedEditorCount: number;
|
||||
private _buffer: model.ITextBuffer;
|
||||
private _bufferDisposable: IDisposable;
|
||||
private _options: model.TextModelResolvedOptions;
|
||||
|
||||
private _isDisposed: boolean;
|
||||
@@ -328,7 +330,9 @@ export class TextModel extends Disposable implements model.ITextModel {
|
||||
this._undoRedoService = undoRedoService;
|
||||
this._attachedEditorCount = 0;
|
||||
|
||||
this._buffer = createTextBuffer(source, creationOptions.defaultEOL);
|
||||
const { textBuffer, disposable } = createTextBuffer(source, creationOptions.defaultEOL);
|
||||
this._buffer = textBuffer;
|
||||
this._bufferDisposable = disposable;
|
||||
|
||||
this._options = TextModel.resolveOptions(this._buffer, creationOptions);
|
||||
|
||||
@@ -386,10 +390,13 @@ export class TextModel extends Disposable implements model.ITextModel {
|
||||
this._tokenization.dispose();
|
||||
this._isDisposed = true;
|
||||
super.dispose();
|
||||
this._bufferDisposable.dispose();
|
||||
this._isDisposing = false;
|
||||
// Manually release reference to previous text buffer to avoid large leaks
|
||||
// in case someone leaks a TextModel reference
|
||||
this._buffer = createTextBuffer('', this._options.defaultEOL);
|
||||
const emptyDisposedTextBuffer = new PieceTreeTextBuffer([], '', '\n', false, false, true, true);
|
||||
emptyDisposedTextBuffer.dispose();
|
||||
this._buffer = emptyDisposedTextBuffer;
|
||||
}
|
||||
|
||||
private _assertNotDisposed(): void {
|
||||
@@ -423,8 +430,8 @@ export class TextModel extends Disposable implements model.ITextModel {
|
||||
return;
|
||||
}
|
||||
|
||||
const textBuffer = createTextBuffer(value, this._options.defaultEOL);
|
||||
this.setValueFromTextBuffer(textBuffer);
|
||||
const { textBuffer, disposable } = createTextBuffer(value, this._options.defaultEOL);
|
||||
this._setValueFromTextBuffer(textBuffer, disposable);
|
||||
}
|
||||
|
||||
private _createContentChanged2(range: Range, rangeOffset: number, rangeLength: number, text: string, isUndoing: boolean, isRedoing: boolean, isFlush: boolean): IModelContentChangedEvent {
|
||||
@@ -443,18 +450,16 @@ export class TextModel extends Disposable implements model.ITextModel {
|
||||
};
|
||||
}
|
||||
|
||||
public setValueFromTextBuffer(textBuffer: model.ITextBuffer): void {
|
||||
private _setValueFromTextBuffer(textBuffer: model.ITextBuffer, textBufferDisposable: IDisposable): void {
|
||||
this._assertNotDisposed();
|
||||
if (textBuffer === null) {
|
||||
// There's nothing to do
|
||||
return;
|
||||
}
|
||||
const oldFullModelRange = this.getFullModelRange();
|
||||
const oldModelValueLength = this.getValueLengthInRange(oldFullModelRange);
|
||||
const endLineNumber = this.getLineCount();
|
||||
const endColumn = this.getLineMaxColumn(endLineNumber);
|
||||
|
||||
this._buffer = textBuffer;
|
||||
this._bufferDisposable.dispose();
|
||||
this._bufferDisposable = textBufferDisposable;
|
||||
this._increaseVersionId();
|
||||
|
||||
// Flush all tokens
|
||||
|
||||
@@ -359,7 +359,7 @@ export class TextModelTokenization extends Disposable {
|
||||
const text = this._textModel.getLineContent(lineIndex + 1);
|
||||
const lineStartState = this._tokenizationStateStore.getBeginState(lineIndex);
|
||||
|
||||
const r = safeTokenize(languageIdentifier, this._tokenizationSupport, text, lineStartState!);
|
||||
const r = safeTokenize(languageIdentifier, this._tokenizationSupport, text, true, lineStartState!);
|
||||
builder.add(lineIndex + 1, r.tokens);
|
||||
this._tokenizationStateStore.setEndState(linesLength, lineIndex, r.endState);
|
||||
lineIndex = this._tokenizationStateStore.invalidLineStartIndex - 1; // -1 because the outer loop increments it
|
||||
@@ -410,13 +410,13 @@ export class TextModelTokenization extends Disposable {
|
||||
const languageIdentifier = this._textModel.getLanguageIdentifier();
|
||||
let state = initialState;
|
||||
for (let i = fakeLines.length - 1; i >= 0; i--) {
|
||||
let r = safeTokenize(languageIdentifier, this._tokenizationSupport, fakeLines[i], state);
|
||||
let r = safeTokenize(languageIdentifier, this._tokenizationSupport, fakeLines[i], false, state);
|
||||
state = r.endState;
|
||||
}
|
||||
|
||||
for (let lineNumber = startLineNumber; lineNumber <= endLineNumber; lineNumber++) {
|
||||
let text = this._textModel.getLineContent(lineNumber);
|
||||
let r = safeTokenize(languageIdentifier, this._tokenizationSupport, text, state);
|
||||
let r = safeTokenize(languageIdentifier, this._tokenizationSupport, text, true, state);
|
||||
builder.add(lineNumber, r.tokens);
|
||||
this._tokenizationStateStore.setFakeTokens(lineNumber - 1);
|
||||
state = r.endState;
|
||||
@@ -443,12 +443,12 @@ function initializeTokenization(textModel: TextModel): [ITokenizationSupport | n
|
||||
return [tokenizationSupport, initialState];
|
||||
}
|
||||
|
||||
function safeTokenize(languageIdentifier: LanguageIdentifier, tokenizationSupport: ITokenizationSupport | null, text: string, state: IState): TokenizationResult2 {
|
||||
function safeTokenize(languageIdentifier: LanguageIdentifier, tokenizationSupport: ITokenizationSupport | null, text: string, hasEOL: boolean, state: IState): TokenizationResult2 {
|
||||
let r: TokenizationResult2 | null = null;
|
||||
|
||||
if (tokenizationSupport) {
|
||||
try {
|
||||
r = tokenizationSupport.tokenize2(text, state.clone(), 0);
|
||||
r = tokenizationSupport.tokenize2(text, hasEOL, state.clone(), 0);
|
||||
} catch (e) {
|
||||
onUnexpectedError(e);
|
||||
}
|
||||
|
||||
@@ -211,9 +211,9 @@ export interface ITokenizationSupport {
|
||||
getInitialState(): IState;
|
||||
|
||||
// add offsetDelta to each of the returned indices
|
||||
tokenize(line: string, state: IState, offsetDelta: number): TokenizationResult;
|
||||
tokenize(line: string, hasEOL: boolean, state: IState, offsetDelta: number): TokenizationResult;
|
||||
|
||||
tokenize2(line: string, state: IState, offsetDelta: number): TokenizationResult2;
|
||||
tokenize2(line: string, hasEOL: boolean, state: IState, offsetDelta: number): TokenizationResult2;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1659,6 +1659,19 @@ export interface CodeLensProvider {
|
||||
resolveCodeLens?(model: model.ITextModel, codeLens: CodeLens, token: CancellationToken): ProviderResult<CodeLens>;
|
||||
}
|
||||
|
||||
export interface InlineHint {
|
||||
text: string;
|
||||
range: IRange;
|
||||
description?: string | IMarkdownString;
|
||||
whitespaceBefore?: boolean;
|
||||
whitespaceAfter?: boolean;
|
||||
}
|
||||
|
||||
export interface InlineHintsProvider {
|
||||
onDidChangeInlineHints?: Event<void> | undefined;
|
||||
provideInlineHints(model: model.ITextModel, range: Range, token: CancellationToken): ProviderResult<InlineHint[]>;
|
||||
}
|
||||
|
||||
export interface SemanticTokensLegend {
|
||||
readonly tokenTypes: string[];
|
||||
readonly tokenModifiers: string[];
|
||||
@@ -1764,6 +1777,11 @@ export const TypeDefinitionProviderRegistry = new LanguageFeatureRegistry<TypeDe
|
||||
*/
|
||||
export const CodeLensProviderRegistry = new LanguageFeatureRegistry<CodeLensProvider>();
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
export const InlineHintsProviderRegistry = new LanguageFeatureRegistry<InlineHintsProvider>();
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
@@ -1876,3 +1894,14 @@ export interface ITokenizationRegistry {
|
||||
* @internal
|
||||
*/
|
||||
export const TokenizationRegistry = new TokenizationRegistryImpl();
|
||||
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
export enum ExternalUriOpenerPriority {
|
||||
None = 0,
|
||||
Option = 1,
|
||||
Default = 2,
|
||||
Preferred = 3,
|
||||
}
|
||||
|
||||
@@ -150,7 +150,7 @@ export interface OnEnterRule {
|
||||
/**
|
||||
* This rule will only execute if the text above the this line matches this regular expression.
|
||||
*/
|
||||
oneLineAboveText?: RegExp;
|
||||
previousLineText?: RegExp;
|
||||
/**
|
||||
* The action to execute.
|
||||
*/
|
||||
|
||||
@@ -101,11 +101,11 @@ export class RichEditSupport {
|
||||
return this._electricCharacter;
|
||||
}
|
||||
|
||||
public onEnter(autoIndent: EditorAutoIndentStrategy, oneLineAboveText: string, beforeEnterText: string, afterEnterText: string): EnterAction | null {
|
||||
public onEnter(autoIndent: EditorAutoIndentStrategy, previousLineText: string, beforeEnterText: string, afterEnterText: string): EnterAction | null {
|
||||
if (!this._onEnterSupport) {
|
||||
return null;
|
||||
}
|
||||
return this._onEnterSupport.onEnter(autoIndent, oneLineAboveText, beforeEnterText, afterEnterText);
|
||||
return this._onEnterSupport.onEnter(autoIndent, previousLineText, beforeEnterText, afterEnterText);
|
||||
}
|
||||
|
||||
private static _mergeConf(prev: LanguageConfiguration | null, current: LanguageConfiguration): LanguageConfiguration {
|
||||
@@ -700,17 +700,17 @@ export class LanguageConfigurationRegistryImpl {
|
||||
afterEnterText = endScopedLineTokens.getLineContent().substr(range.endColumn - 1 - scopedLineTokens.firstCharOffset);
|
||||
}
|
||||
|
||||
let oneLineAboveText = '';
|
||||
let previousLineText = '';
|
||||
if (range.startLineNumber > 1 && scopedLineTokens.firstCharOffset === 0) {
|
||||
// This is not the first line and the entire line belongs to this mode
|
||||
const oneLineAboveScopedLineTokens = this.getScopedLineTokens(model, range.startLineNumber - 1);
|
||||
if (oneLineAboveScopedLineTokens.languageId === scopedLineTokens.languageId) {
|
||||
// The line above ends with text belonging to the same mode
|
||||
oneLineAboveText = oneLineAboveScopedLineTokens.getLineContent();
|
||||
previousLineText = oneLineAboveScopedLineTokens.getLineContent();
|
||||
}
|
||||
}
|
||||
|
||||
const enterResult = richEditSupport.onEnter(autoIndent, oneLineAboveText, beforeEnterText, afterEnterText);
|
||||
const enterResult = richEditSupport.onEnter(autoIndent, previousLineText, beforeEnterText, afterEnterText);
|
||||
if (!enterResult) {
|
||||
return null;
|
||||
}
|
||||
@@ -729,6 +729,8 @@ export class LanguageConfigurationRegistryImpl {
|
||||
} else {
|
||||
appendText = '';
|
||||
}
|
||||
} else if (indentAction === IndentAction.Indent) {
|
||||
appendText = '\t' + appendText;
|
||||
}
|
||||
|
||||
let indentation = this.getIndentationAtPosition(model, range.startLineNumber, range.startColumn);
|
||||
|
||||
@@ -58,11 +58,12 @@ export const ModesRegistry = new EditorModesRegistry();
|
||||
Registry.add(Extensions.ModesRegistry, ModesRegistry);
|
||||
|
||||
export const PLAINTEXT_MODE_ID = 'plaintext';
|
||||
export const PLAINTEXT_EXTENSION = '.txt';
|
||||
export const PLAINTEXT_LANGUAGE_IDENTIFIER = new LanguageIdentifier(PLAINTEXT_MODE_ID, LanguageId.PlainText);
|
||||
|
||||
ModesRegistry.registerLanguage({
|
||||
id: PLAINTEXT_MODE_ID,
|
||||
extensions: ['.txt'],
|
||||
extensions: [PLAINTEXT_EXTENSION],
|
||||
aliases: [nls.localize('plainText.alias', "Plain Text"), 'text'],
|
||||
mimetypes: ['text/plain']
|
||||
});
|
||||
|
||||
@@ -49,7 +49,7 @@ export class OnEnterSupport {
|
||||
this._regExpRules = opts.onEnterRules || [];
|
||||
}
|
||||
|
||||
public onEnter(autoIndent: EditorAutoIndentStrategy, oneLineAboveText: string, beforeEnterText: string, afterEnterText: string): EnterAction | null {
|
||||
public onEnter(autoIndent: EditorAutoIndentStrategy, previousLineText: string, beforeEnterText: string, afterEnterText: string): EnterAction | null {
|
||||
// (1): `regExpRules`
|
||||
if (autoIndent >= EditorAutoIndentStrategy.Advanced) {
|
||||
for (let i = 0, len = this._regExpRules.length; i < len; i++) {
|
||||
@@ -61,8 +61,8 @@ export class OnEnterSupport {
|
||||
reg: rule.afterText,
|
||||
text: afterEnterText
|
||||
}, {
|
||||
reg: rule.oneLineAboveText,
|
||||
text: oneLineAboveText
|
||||
reg: rule.previousLineText,
|
||||
text: previousLineText
|
||||
}].every((obj): boolean => {
|
||||
return obj.reg ? obj.reg.test(obj.text) : true;
|
||||
});
|
||||
|
||||
@@ -12,12 +12,12 @@ import { NULL_STATE, nullTokenize2 } from 'vs/editor/common/modes/nullMode';
|
||||
|
||||
export interface IReducedTokenizationSupport {
|
||||
getInitialState(): IState;
|
||||
tokenize2(line: string, state: IState, offsetDelta: number): TokenizationResult2;
|
||||
tokenize2(line: string, hasEOL: boolean, state: IState, offsetDelta: number): TokenizationResult2;
|
||||
}
|
||||
|
||||
const fallback: IReducedTokenizationSupport = {
|
||||
getInitialState: () => NULL_STATE,
|
||||
tokenize2: (buffer: string, state: IState, deltaOffset: number) => nullTokenize2(LanguageId.Null, buffer, state, deltaOffset)
|
||||
tokenize2: (buffer: string, hasEOL: boolean, state: IState, deltaOffset: number) => nullTokenize2(LanguageId.Null, buffer, state, deltaOffset)
|
||||
};
|
||||
|
||||
export function tokenizeToString(text: string, tokenizationSupport: IReducedTokenizationSupport = fallback): string {
|
||||
@@ -110,7 +110,7 @@ function _tokenizeToString(text: string, tokenizationSupport: IReducedTokenizati
|
||||
result += `<br/>`;
|
||||
}
|
||||
|
||||
let tokenizationResult = tokenizationSupport.tokenize2(line, currentState, 0);
|
||||
let tokenizationResult = tokenizationSupport.tokenize2(line, true, currentState, 0);
|
||||
LineTokens.convertToEndOffset(tokenizationResult.tokens, line.length);
|
||||
let lineTokens = new LineTokens(tokenizationResult.tokens, line);
|
||||
let viewLineTokens = lineTokens.inflate();
|
||||
|
||||
160
lib/vscode/src/vs/editor/common/services/getSemanticTokens.ts
Normal file
160
lib/vscode/src/vs/editor/common/services/getSemanticTokens.ts
Normal file
@@ -0,0 +1,160 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { CancellationToken } from 'vs/base/common/cancellation';
|
||||
import { onUnexpectedExternalError } from 'vs/base/common/errors';
|
||||
import { URI } from 'vs/base/common/uri';
|
||||
import { ITextModel } from 'vs/editor/common/model';
|
||||
import { DocumentSemanticTokensProviderRegistry, DocumentSemanticTokensProvider, SemanticTokens, SemanticTokensEdits, SemanticTokensLegend, DocumentRangeSemanticTokensProviderRegistry, DocumentRangeSemanticTokensProvider } from 'vs/editor/common/modes';
|
||||
import { IModelService } from 'vs/editor/common/services/modelService';
|
||||
import { CommandsRegistry, ICommandService } from 'vs/platform/commands/common/commands';
|
||||
import { assertType } from 'vs/base/common/types';
|
||||
import { VSBuffer } from 'vs/base/common/buffer';
|
||||
import { encodeSemanticTokensDto } from 'vs/editor/common/services/semanticTokensDto';
|
||||
import { Range } from 'vs/editor/common/core/range';
|
||||
|
||||
export function isSemanticTokens(v: SemanticTokens | SemanticTokensEdits): v is SemanticTokens {
|
||||
return v && !!((<SemanticTokens>v).data);
|
||||
}
|
||||
|
||||
export function isSemanticTokensEdits(v: SemanticTokens | SemanticTokensEdits): v is SemanticTokensEdits {
|
||||
return v && Array.isArray((<SemanticTokensEdits>v).edits);
|
||||
}
|
||||
|
||||
export interface IDocumentSemanticTokensResult {
|
||||
provider: DocumentSemanticTokensProvider;
|
||||
request: Promise<SemanticTokens | SemanticTokensEdits | null | undefined>;
|
||||
}
|
||||
|
||||
export function getDocumentSemanticTokens(model: ITextModel, lastResultId: string | null, token: CancellationToken): IDocumentSemanticTokensResult | null {
|
||||
const provider = _getDocumentSemanticTokensProvider(model);
|
||||
if (!provider) {
|
||||
return null;
|
||||
}
|
||||
return {
|
||||
provider: provider,
|
||||
request: Promise.resolve(provider.provideDocumentSemanticTokens(model, lastResultId, token))
|
||||
};
|
||||
}
|
||||
|
||||
function _getDocumentSemanticTokensProvider(model: ITextModel): DocumentSemanticTokensProvider | null {
|
||||
const result = DocumentSemanticTokensProviderRegistry.ordered(model);
|
||||
return (result.length > 0 ? result[0] : null);
|
||||
}
|
||||
|
||||
export function getDocumentRangeSemanticTokensProvider(model: ITextModel): DocumentRangeSemanticTokensProvider | null {
|
||||
const result = DocumentRangeSemanticTokensProviderRegistry.ordered(model);
|
||||
return (result.length > 0 ? result[0] : null);
|
||||
}
|
||||
|
||||
CommandsRegistry.registerCommand('_provideDocumentSemanticTokensLegend', async (accessor, ...args): Promise<SemanticTokensLegend | undefined> => {
|
||||
const [uri] = args;
|
||||
assertType(uri instanceof URI);
|
||||
|
||||
const model = accessor.get(IModelService).getModel(uri);
|
||||
if (!model) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
const provider = _getDocumentSemanticTokensProvider(model);
|
||||
if (!provider) {
|
||||
// there is no provider => fall back to a document range semantic tokens provider
|
||||
return accessor.get(ICommandService).executeCommand('_provideDocumentRangeSemanticTokensLegend', uri);
|
||||
}
|
||||
|
||||
return provider.getLegend();
|
||||
});
|
||||
|
||||
CommandsRegistry.registerCommand('_provideDocumentSemanticTokens', async (accessor, ...args): Promise<VSBuffer | undefined> => {
|
||||
const [uri] = args;
|
||||
assertType(uri instanceof URI);
|
||||
|
||||
const model = accessor.get(IModelService).getModel(uri);
|
||||
if (!model) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
const r = getDocumentSemanticTokens(model, null, CancellationToken.None);
|
||||
if (!r) {
|
||||
// there is no provider => fall back to a document range semantic tokens provider
|
||||
return accessor.get(ICommandService).executeCommand('_provideDocumentRangeSemanticTokens', uri, model.getFullModelRange());
|
||||
}
|
||||
|
||||
const { provider, request } = r;
|
||||
|
||||
let result: SemanticTokens | SemanticTokensEdits | null | undefined;
|
||||
try {
|
||||
result = await request;
|
||||
} catch (err) {
|
||||
onUnexpectedExternalError(err);
|
||||
return undefined;
|
||||
}
|
||||
|
||||
if (!result || !isSemanticTokens(result)) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
const buff = encodeSemanticTokensDto({
|
||||
id: 0,
|
||||
type: 'full',
|
||||
data: result.data
|
||||
});
|
||||
if (result.resultId) {
|
||||
provider.releaseDocumentSemanticTokens(result.resultId);
|
||||
}
|
||||
return buff;
|
||||
});
|
||||
|
||||
CommandsRegistry.registerCommand('_provideDocumentRangeSemanticTokensLegend', async (accessor, ...args): Promise<SemanticTokensLegend | undefined> => {
|
||||
const [uri] = args;
|
||||
assertType(uri instanceof URI);
|
||||
|
||||
const model = accessor.get(IModelService).getModel(uri);
|
||||
if (!model) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
const provider = getDocumentRangeSemanticTokensProvider(model);
|
||||
if (!provider) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
return provider.getLegend();
|
||||
});
|
||||
|
||||
CommandsRegistry.registerCommand('_provideDocumentRangeSemanticTokens', async (accessor, ...args): Promise<VSBuffer | undefined> => {
|
||||
const [uri, range] = args;
|
||||
assertType(uri instanceof URI);
|
||||
assertType(Range.isIRange(range));
|
||||
|
||||
const model = accessor.get(IModelService).getModel(uri);
|
||||
if (!model) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
const provider = getDocumentRangeSemanticTokensProvider(model);
|
||||
if (!provider) {
|
||||
// there is no provider
|
||||
return undefined;
|
||||
}
|
||||
|
||||
let result: SemanticTokens | null | undefined;
|
||||
try {
|
||||
result = await provider.provideDocumentRangeSemanticTokens(model, Range.lift(range), CancellationToken.None);
|
||||
} catch (err) {
|
||||
onUnexpectedExternalError(err);
|
||||
return undefined;
|
||||
}
|
||||
|
||||
if (!result || !isSemanticTokens(result)) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
return encodeSemanticTokensDto({
|
||||
id: 0,
|
||||
type: 'full',
|
||||
data: result.data
|
||||
});
|
||||
});
|
||||
@@ -87,13 +87,13 @@ export class MarkerDecorationsService extends Disposable implements IMarkerDecor
|
||||
this._markerDecorations.clear();
|
||||
}
|
||||
|
||||
getMarker(model: ITextModel, decoration: IModelDecoration): IMarker | null {
|
||||
const markerDecorations = this._markerDecorations.get(MODEL_ID(model.uri));
|
||||
getMarker(uri: URI, decoration: IModelDecoration): IMarker | null {
|
||||
const markerDecorations = this._markerDecorations.get(MODEL_ID(uri));
|
||||
return markerDecorations ? (markerDecorations.getMarker(decoration) || null) : null;
|
||||
}
|
||||
|
||||
getLiveMarkers(model: ITextModel): [Range, IMarker][] {
|
||||
const markerDecorations = this._markerDecorations.get(MODEL_ID(model.uri));
|
||||
getLiveMarkers(uri: URI): [Range, IMarker][] {
|
||||
const markerDecorations = this._markerDecorations.get(MODEL_ID(uri));
|
||||
return markerDecorations ? markerDecorations.getMarkers() : [];
|
||||
}
|
||||
|
||||
|
||||
@@ -8,6 +8,7 @@ import { createDecorator } from 'vs/platform/instantiation/common/instantiation'
|
||||
import { IMarker } from 'vs/platform/markers/common/markers';
|
||||
import { Event } from 'vs/base/common/event';
|
||||
import { Range } from 'vs/editor/common/core/range';
|
||||
import { URI } from 'vs/base/common/uri';
|
||||
|
||||
export const IMarkerDecorationsService = createDecorator<IMarkerDecorationsService>('markerDecorationsService');
|
||||
|
||||
@@ -16,7 +17,7 @@ export interface IMarkerDecorationsService {
|
||||
|
||||
onDidChangeMarker: Event<ITextModel>;
|
||||
|
||||
getMarker(model: ITextModel, decoration: IModelDecoration): IMarker | null;
|
||||
getMarker(uri: URI, decoration: IModelDecoration): IMarker | null;
|
||||
|
||||
getLiveMarkers(model: ITextModel): [Range, IMarker][];
|
||||
getLiveMarkers(uri: URI): [Range, IMarker][];
|
||||
}
|
||||
|
||||
@@ -50,7 +50,7 @@ export interface IModeService {
|
||||
// --- instantiation
|
||||
create(commaSeparatedMimetypesOrCommaSeparatedIds: string | undefined): ILanguageSelection;
|
||||
createByLanguageName(languageName: string): ILanguageSelection;
|
||||
createByFilepathOrFirstLine(rsource: URI | null, firstLine?: string): ILanguageSelection;
|
||||
createByFilepathOrFirstLine(resource: URI | null, firstLine?: string): ILanguageSelection;
|
||||
|
||||
triggerMode(commaSeparatedMimetypesOrCommaSeparatedIds: string): void;
|
||||
}
|
||||
|
||||
@@ -40,23 +40,24 @@ class LanguageSelection extends Disposable implements ILanguageSelection {
|
||||
}
|
||||
}
|
||||
|
||||
export class ModeServiceImpl implements IModeService {
|
||||
export class ModeServiceImpl extends Disposable implements IModeService {
|
||||
public _serviceBrand: undefined;
|
||||
|
||||
private readonly _instantiatedModes: { [modeId: string]: IMode; };
|
||||
private readonly _registry: LanguagesRegistry;
|
||||
|
||||
private readonly _onDidCreateMode = new Emitter<IMode>();
|
||||
private readonly _onDidCreateMode = this._register(new Emitter<IMode>());
|
||||
public readonly onDidCreateMode: Event<IMode> = this._onDidCreateMode.event;
|
||||
|
||||
protected readonly _onLanguagesMaybeChanged = new Emitter<void>();
|
||||
protected readonly _onLanguagesMaybeChanged = this._register(new Emitter<void>());
|
||||
public readonly onLanguagesMaybeChanged: Event<void> = this._onLanguagesMaybeChanged.event;
|
||||
|
||||
constructor(warnOnOverwrite = false) {
|
||||
super();
|
||||
this._instantiatedModes = {};
|
||||
|
||||
this._registry = new LanguagesRegistry(true, warnOnOverwrite);
|
||||
this._registry.onDidChange(() => this._onLanguagesMaybeChanged.fire());
|
||||
this._registry = this._register(new LanguagesRegistry(true, warnOnOverwrite));
|
||||
this._register(this._registry.onDidChange(() => this._onLanguagesMaybeChanged.fire()));
|
||||
}
|
||||
|
||||
protected _onReady(): Promise<boolean> {
|
||||
|
||||
@@ -29,6 +29,7 @@ import { StringSHA1 } from 'vs/base/common/hash';
|
||||
import { EditStackElement, isEditStackElement } from 'vs/editor/common/model/editStack';
|
||||
import { Schemas } from 'vs/base/common/network';
|
||||
import { SemanticTokensProviderStyling, toMultilineTokens2 } from 'vs/editor/common/services/semanticTokensProviderStyling';
|
||||
import { getDocumentSemanticTokens, isSemanticTokens, isSemanticTokensEdits } from 'vs/editor/common/services/getSemanticTokens';
|
||||
|
||||
export interface IEditorSemanticHighlightingOptions {
|
||||
enabled: true | false | 'configuredByTheme';
|
||||
@@ -412,10 +413,11 @@ export class ModelServiceImpl extends Disposable implements IModelService {
|
||||
|
||||
public updateModel(model: ITextModel, value: string | ITextBufferFactory): void {
|
||||
const options = this.getCreationOptions(model.getLanguageIdentifier().language, model.uri, model.isForSimpleWidget);
|
||||
const textBuffer = createTextBuffer(value, options.defaultEOL);
|
||||
const { textBuffer, disposable } = createTextBuffer(value, options.defaultEOL);
|
||||
|
||||
// Return early if the text is already set in that form
|
||||
if (model.equalsTextBuffer(textBuffer)) {
|
||||
disposable.dispose();
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -428,6 +430,7 @@ export class ModelServiceImpl extends Disposable implements IModelService {
|
||||
() => []
|
||||
);
|
||||
model.pushStackElement();
|
||||
disposable.dispose();
|
||||
}
|
||||
|
||||
private static _commonPrefix(a: ILineSequence, aLen: number, aDelta: number, b: ILineSequence, bLen: number, bDelta: number): number {
|
||||
@@ -513,58 +516,6 @@ export class ModelServiceImpl extends Disposable implements IModelService {
|
||||
if (!modelData) {
|
||||
return;
|
||||
}
|
||||
const model = modelData.model;
|
||||
const sharesUndoRedoStack = (this._undoRedoService.getUriComparisonKey(model.uri) !== model.uri.toString());
|
||||
let maintainUndoRedoStack = false;
|
||||
let heapSize = 0;
|
||||
if (sharesUndoRedoStack || (this._shouldRestoreUndoStack() && schemaShouldMaintainUndoRedoElements(resource))) {
|
||||
const elements = this._undoRedoService.getElements(resource);
|
||||
if (elements.past.length > 0 || elements.future.length > 0) {
|
||||
for (const element of elements.past) {
|
||||
if (isEditStackElement(element) && element.matchesResource(resource)) {
|
||||
maintainUndoRedoStack = true;
|
||||
heapSize += element.heapSize(resource);
|
||||
element.setModel(resource); // remove reference from text buffer instance
|
||||
}
|
||||
}
|
||||
for (const element of elements.future) {
|
||||
if (isEditStackElement(element) && element.matchesResource(resource)) {
|
||||
maintainUndoRedoStack = true;
|
||||
heapSize += element.heapSize(resource);
|
||||
element.setModel(resource); // remove reference from text buffer instance
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!maintainUndoRedoStack) {
|
||||
if (!sharesUndoRedoStack) {
|
||||
const initialUndoRedoSnapshot = modelData.model.getInitialUndoRedoSnapshot();
|
||||
if (initialUndoRedoSnapshot !== null) {
|
||||
this._undoRedoService.restoreSnapshot(initialUndoRedoSnapshot);
|
||||
}
|
||||
}
|
||||
modelData.model.dispose();
|
||||
return;
|
||||
}
|
||||
|
||||
const maxMemory = ModelServiceImpl.MAX_MEMORY_FOR_CLOSED_FILES_UNDO_STACK;
|
||||
if (!sharesUndoRedoStack && heapSize > maxMemory) {
|
||||
// the undo stack for this file would never fit in the configured memory, so don't bother with it.
|
||||
const initialUndoRedoSnapshot = modelData.model.getInitialUndoRedoSnapshot();
|
||||
if (initialUndoRedoSnapshot !== null) {
|
||||
this._undoRedoService.restoreSnapshot(initialUndoRedoSnapshot);
|
||||
}
|
||||
modelData.model.dispose();
|
||||
return;
|
||||
}
|
||||
|
||||
this._ensureDisposedModelsHeapSize(maxMemory - heapSize);
|
||||
|
||||
// We only invalidate the elements, but they remain in the undo-redo service.
|
||||
this._undoRedoService.setElementsValidFlag(resource, false, (element) => (isEditStackElement(element) && element.matchesResource(resource)));
|
||||
this._insertDisposedModel(new DisposedModelInfo(resource, modelData.model.getInitialUndoRedoSnapshot(), Date.now(), sharesUndoRedoStack, heapSize, computeModelSha1(model), model.getVersionId(), model.getAlternativeVersionId()));
|
||||
|
||||
modelData.model.dispose();
|
||||
}
|
||||
|
||||
@@ -599,6 +550,50 @@ export class ModelServiceImpl extends Disposable implements IModelService {
|
||||
const modelId = MODEL_ID(model.uri);
|
||||
const modelData = this._models[modelId];
|
||||
|
||||
const sharesUndoRedoStack = (this._undoRedoService.getUriComparisonKey(model.uri) !== model.uri.toString());
|
||||
let maintainUndoRedoStack = false;
|
||||
let heapSize = 0;
|
||||
if (sharesUndoRedoStack || (this._shouldRestoreUndoStack() && schemaShouldMaintainUndoRedoElements(model.uri))) {
|
||||
const elements = this._undoRedoService.getElements(model.uri);
|
||||
if (elements.past.length > 0 || elements.future.length > 0) {
|
||||
for (const element of elements.past) {
|
||||
if (isEditStackElement(element) && element.matchesResource(model.uri)) {
|
||||
maintainUndoRedoStack = true;
|
||||
heapSize += element.heapSize(model.uri);
|
||||
element.setModel(model.uri); // remove reference from text buffer instance
|
||||
}
|
||||
}
|
||||
for (const element of elements.future) {
|
||||
if (isEditStackElement(element) && element.matchesResource(model.uri)) {
|
||||
maintainUndoRedoStack = true;
|
||||
heapSize += element.heapSize(model.uri);
|
||||
element.setModel(model.uri); // remove reference from text buffer instance
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const maxMemory = ModelServiceImpl.MAX_MEMORY_FOR_CLOSED_FILES_UNDO_STACK;
|
||||
if (!maintainUndoRedoStack) {
|
||||
if (!sharesUndoRedoStack) {
|
||||
const initialUndoRedoSnapshot = modelData.model.getInitialUndoRedoSnapshot();
|
||||
if (initialUndoRedoSnapshot !== null) {
|
||||
this._undoRedoService.restoreSnapshot(initialUndoRedoSnapshot);
|
||||
}
|
||||
}
|
||||
} else if (!sharesUndoRedoStack && heapSize > maxMemory) {
|
||||
// the undo stack for this file would never fit in the configured memory, so don't bother with it.
|
||||
const initialUndoRedoSnapshot = modelData.model.getInitialUndoRedoSnapshot();
|
||||
if (initialUndoRedoSnapshot !== null) {
|
||||
this._undoRedoService.restoreSnapshot(initialUndoRedoSnapshot);
|
||||
}
|
||||
} else {
|
||||
this._ensureDisposedModelsHeapSize(maxMemory - heapSize);
|
||||
// We only invalidate the elements, but they remain in the undo-redo service.
|
||||
this._undoRedoService.setElementsValidFlag(model.uri, false, (element) => (isEditStackElement(element) && element.matchesResource(model.uri)));
|
||||
this._insertDisposedModel(new DisposedModelInfo(model.uri, modelData.model.getInitialUndoRedoSnapshot(), Date.now(), sharesUndoRedoStack, heapSize, computeModelSha1(model), model.getVersionId(), model.getAlternativeVersionId()));
|
||||
}
|
||||
|
||||
delete this._models[modelId];
|
||||
modelData.dispose();
|
||||
|
||||
@@ -718,7 +713,9 @@ class SemanticTokensResponse {
|
||||
}
|
||||
}
|
||||
|
||||
class ModelSemanticColoring extends Disposable {
|
||||
export class ModelSemanticColoring extends Disposable {
|
||||
|
||||
public static FETCH_DOCUMENT_SEMANTIC_TOKENS_DELAY = 300;
|
||||
|
||||
private _isDisposed: boolean;
|
||||
private readonly _model: ITextModel;
|
||||
@@ -734,7 +731,7 @@ class ModelSemanticColoring extends Disposable {
|
||||
this._isDisposed = false;
|
||||
this._model = model;
|
||||
this._semanticStyling = stylingProvider;
|
||||
this._fetchDocumentSemanticTokens = this._register(new RunOnceScheduler(() => this._fetchDocumentSemanticTokensNow(), 300));
|
||||
this._fetchDocumentSemanticTokens = this._register(new RunOnceScheduler(() => this._fetchDocumentSemanticTokensNow(), ModelSemanticColoring.FETCH_DOCUMENT_SEMANTIC_TOKENS_DELAY));
|
||||
this._currentDocumentResponse = null;
|
||||
this._currentDocumentRequestCancellationTokenSource = null;
|
||||
this._documentProvidersChangeListeners = [];
|
||||
@@ -788,15 +785,21 @@ class ModelSemanticColoring extends Disposable {
|
||||
// there is already a request running, let it finish...
|
||||
return;
|
||||
}
|
||||
const provider = this._getSemanticColoringProvider();
|
||||
if (!provider) {
|
||||
|
||||
const cancellationTokenSource = new CancellationTokenSource();
|
||||
const lastResultId = this._currentDocumentResponse ? this._currentDocumentResponse.resultId || null : null;
|
||||
const r = getDocumentSemanticTokens(this._model, lastResultId, cancellationTokenSource.token);
|
||||
if (!r) {
|
||||
// there is no provider
|
||||
if (this._currentDocumentResponse) {
|
||||
// there are semantic tokens set
|
||||
this._model.setSemanticTokens(null, false);
|
||||
}
|
||||
return;
|
||||
}
|
||||
this._currentDocumentRequestCancellationTokenSource = new CancellationTokenSource();
|
||||
|
||||
const { provider, request } = r;
|
||||
this._currentDocumentRequestCancellationTokenSource = cancellationTokenSource;
|
||||
|
||||
const pendingChanges: IModelContentChangedEvent[] = [];
|
||||
const contentChangeListener = this._model.onDidChangeContent((e) => {
|
||||
@@ -805,15 +808,13 @@ class ModelSemanticColoring extends Disposable {
|
||||
|
||||
const styling = this._semanticStyling.get(provider);
|
||||
|
||||
const lastResultId = this._currentDocumentResponse ? this._currentDocumentResponse.resultId || null : null;
|
||||
const request = Promise.resolve(provider.provideDocumentSemanticTokens(this._model, lastResultId, this._currentDocumentRequestCancellationTokenSource.token));
|
||||
|
||||
request.then((res) => {
|
||||
this._currentDocumentRequestCancellationTokenSource = null;
|
||||
contentChangeListener.dispose();
|
||||
this._setDocumentSemanticTokens(provider, res || null, styling, pendingChanges);
|
||||
}, (err) => {
|
||||
if (!err || typeof err.message !== 'string' || err.message.indexOf('busy') === -1) {
|
||||
const isExpectedError = err && (errors.isPromiseCanceledError(err) || (typeof err.message === 'string' && err.message.indexOf('busy') !== -1));
|
||||
if (!isExpectedError) {
|
||||
errors.onUnexpectedError(err);
|
||||
}
|
||||
|
||||
@@ -831,14 +832,6 @@ class ModelSemanticColoring extends Disposable {
|
||||
});
|
||||
}
|
||||
|
||||
private static _isSemanticTokens(v: SemanticTokens | SemanticTokensEdits): v is SemanticTokens {
|
||||
return v && !!((<SemanticTokens>v).data);
|
||||
}
|
||||
|
||||
private static _isSemanticTokensEdits(v: SemanticTokens | SemanticTokensEdits): v is SemanticTokensEdits {
|
||||
return v && Array.isArray((<SemanticTokensEdits>v).edits);
|
||||
}
|
||||
|
||||
private static _copy(src: Uint32Array, srcOffset: number, dest: Uint32Array, destOffset: number, length: number): void {
|
||||
for (let i = 0; i < length; i++) {
|
||||
dest[destOffset + i] = src[srcOffset + i];
|
||||
@@ -847,6 +840,12 @@ class ModelSemanticColoring extends Disposable {
|
||||
|
||||
private _setDocumentSemanticTokens(provider: DocumentSemanticTokensProvider | null, tokens: SemanticTokens | SemanticTokensEdits | null, styling: SemanticTokensProviderStyling | null, pendingChanges: IModelContentChangedEvent[]): void {
|
||||
const currentResponse = this._currentDocumentResponse;
|
||||
const rescheduleIfNeeded = () => {
|
||||
if (pendingChanges.length > 0 && !this._fetchDocumentSemanticTokens.isScheduled()) {
|
||||
this._fetchDocumentSemanticTokens.schedule();
|
||||
}
|
||||
};
|
||||
|
||||
if (this._currentDocumentResponse) {
|
||||
this._currentDocumentResponse.dispose();
|
||||
this._currentDocumentResponse = null;
|
||||
@@ -864,10 +863,11 @@ class ModelSemanticColoring extends Disposable {
|
||||
}
|
||||
if (!tokens) {
|
||||
this._model.setSemanticTokens(null, true);
|
||||
rescheduleIfNeeded();
|
||||
return;
|
||||
}
|
||||
|
||||
if (ModelSemanticColoring._isSemanticTokensEdits(tokens)) {
|
||||
if (isSemanticTokensEdits(tokens)) {
|
||||
if (!currentResponse) {
|
||||
// not possible!
|
||||
this._model.setSemanticTokens(null, true);
|
||||
@@ -918,7 +918,7 @@ class ModelSemanticColoring extends Disposable {
|
||||
}
|
||||
}
|
||||
|
||||
if (ModelSemanticColoring._isSemanticTokens(tokens)) {
|
||||
if (isSemanticTokens(tokens)) {
|
||||
|
||||
this._currentDocumentResponse = new SemanticTokensResponse(provider, tokens.resultId, tokens.data);
|
||||
|
||||
@@ -937,21 +937,13 @@ class ModelSemanticColoring extends Disposable {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!this._fetchDocumentSemanticTokens.isScheduled()) {
|
||||
this._fetchDocumentSemanticTokens.schedule();
|
||||
}
|
||||
}
|
||||
|
||||
this._model.setSemanticTokens(result, true);
|
||||
return;
|
||||
} else {
|
||||
this._model.setSemanticTokens(null, true);
|
||||
}
|
||||
|
||||
this._model.setSemanticTokens(null, true);
|
||||
}
|
||||
|
||||
private _getSemanticColoringProvider(): DocumentSemanticTokensProvider | null {
|
||||
const result = DocumentSemanticTokensProviderRegistry.ordered(this._model);
|
||||
return (result.length > 0 ? result[0] : null);
|
||||
rescheduleIfNeeded();
|
||||
}
|
||||
}
|
||||
|
||||
152
lib/vscode/src/vs/editor/common/services/semanticTokensDto.ts
Normal file
152
lib/vscode/src/vs/editor/common/services/semanticTokensDto.ts
Normal file
@@ -0,0 +1,152 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { VSBuffer } from 'vs/base/common/buffer';
|
||||
import * as platform from 'vs/base/common/platform';
|
||||
|
||||
export interface IFullSemanticTokensDto {
|
||||
id: number;
|
||||
type: 'full';
|
||||
data: Uint32Array;
|
||||
}
|
||||
|
||||
export interface IDeltaSemanticTokensDto {
|
||||
id: number;
|
||||
type: 'delta';
|
||||
deltas: { start: number; deleteCount: number; data?: Uint32Array; }[];
|
||||
}
|
||||
|
||||
export type ISemanticTokensDto = IFullSemanticTokensDto | IDeltaSemanticTokensDto;
|
||||
|
||||
const enum EncodedSemanticTokensType {
|
||||
Full = 1,
|
||||
Delta = 2
|
||||
}
|
||||
|
||||
function reverseEndianness(arr: Uint8Array): void {
|
||||
for (let i = 0, len = arr.length; i < len; i += 4) {
|
||||
// flip bytes 0<->3 and 1<->2
|
||||
const b0 = arr[i + 0];
|
||||
const b1 = arr[i + 1];
|
||||
const b2 = arr[i + 2];
|
||||
const b3 = arr[i + 3];
|
||||
arr[i + 0] = b3;
|
||||
arr[i + 1] = b2;
|
||||
arr[i + 2] = b1;
|
||||
arr[i + 3] = b0;
|
||||
}
|
||||
}
|
||||
|
||||
function toLittleEndianBuffer(arr: Uint32Array): VSBuffer {
|
||||
const uint8Arr = new Uint8Array(arr.buffer, arr.byteOffset, arr.length * 4);
|
||||
if (!platform.isLittleEndian()) {
|
||||
// the byte order must be changed
|
||||
reverseEndianness(uint8Arr);
|
||||
}
|
||||
return VSBuffer.wrap(uint8Arr);
|
||||
}
|
||||
|
||||
function fromLittleEndianBuffer(buff: VSBuffer): Uint32Array {
|
||||
const uint8Arr = buff.buffer;
|
||||
if (!platform.isLittleEndian()) {
|
||||
// the byte order must be changed
|
||||
reverseEndianness(uint8Arr);
|
||||
}
|
||||
if (uint8Arr.byteOffset % 4 === 0) {
|
||||
return new Uint32Array(uint8Arr.buffer, uint8Arr.byteOffset, uint8Arr.length / 4);
|
||||
} else {
|
||||
// unaligned memory access doesn't work on all platforms
|
||||
const data = new Uint8Array(uint8Arr.byteLength);
|
||||
data.set(uint8Arr);
|
||||
return new Uint32Array(data.buffer, data.byteOffset, data.length / 4);
|
||||
}
|
||||
}
|
||||
|
||||
export function encodeSemanticTokensDto(semanticTokens: ISemanticTokensDto): VSBuffer {
|
||||
const dest = new Uint32Array(encodeSemanticTokensDtoSize(semanticTokens));
|
||||
let offset = 0;
|
||||
dest[offset++] = semanticTokens.id;
|
||||
if (semanticTokens.type === 'full') {
|
||||
dest[offset++] = EncodedSemanticTokensType.Full;
|
||||
dest[offset++] = semanticTokens.data.length;
|
||||
dest.set(semanticTokens.data, offset); offset += semanticTokens.data.length;
|
||||
} else {
|
||||
dest[offset++] = EncodedSemanticTokensType.Delta;
|
||||
dest[offset++] = semanticTokens.deltas.length;
|
||||
for (const delta of semanticTokens.deltas) {
|
||||
dest[offset++] = delta.start;
|
||||
dest[offset++] = delta.deleteCount;
|
||||
if (delta.data) {
|
||||
dest[offset++] = delta.data.length;
|
||||
dest.set(delta.data, offset); offset += delta.data.length;
|
||||
} else {
|
||||
dest[offset++] = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
return toLittleEndianBuffer(dest);
|
||||
}
|
||||
|
||||
function encodeSemanticTokensDtoSize(semanticTokens: ISemanticTokensDto): number {
|
||||
let result = 0;
|
||||
result += (
|
||||
+ 1 // id
|
||||
+ 1 // type
|
||||
);
|
||||
if (semanticTokens.type === 'full') {
|
||||
result += (
|
||||
+ 1 // data length
|
||||
+ semanticTokens.data.length
|
||||
);
|
||||
} else {
|
||||
result += (
|
||||
+ 1 // delta count
|
||||
);
|
||||
result += (
|
||||
+ 1 // start
|
||||
+ 1 // deleteCount
|
||||
+ 1 // data length
|
||||
) * semanticTokens.deltas.length;
|
||||
for (const delta of semanticTokens.deltas) {
|
||||
if (delta.data) {
|
||||
result += delta.data.length;
|
||||
}
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
export function decodeSemanticTokensDto(_buff: VSBuffer): ISemanticTokensDto {
|
||||
const src = fromLittleEndianBuffer(_buff);
|
||||
let offset = 0;
|
||||
const id = src[offset++];
|
||||
const type: EncodedSemanticTokensType = src[offset++];
|
||||
if (type === EncodedSemanticTokensType.Full) {
|
||||
const length = src[offset++];
|
||||
const data = src.subarray(offset, offset + length); offset += length;
|
||||
return {
|
||||
id: id,
|
||||
type: 'full',
|
||||
data: data
|
||||
};
|
||||
}
|
||||
const deltaCount = src[offset++];
|
||||
let deltas: { start: number; deleteCount: number; data?: Uint32Array; }[] = [];
|
||||
for (let i = 0; i < deltaCount; i++) {
|
||||
const start = src[offset++];
|
||||
const deleteCount = src[offset++];
|
||||
const length = src[offset++];
|
||||
let data: Uint32Array | undefined;
|
||||
if (length > 0) {
|
||||
data = src.subarray(offset, offset + length); offset += length;
|
||||
}
|
||||
deltas[i] = { start, deleteCount, data };
|
||||
}
|
||||
return {
|
||||
id: id,
|
||||
type: 'delta',
|
||||
deltas: deltas
|
||||
};
|
||||
}
|
||||
@@ -287,11 +287,12 @@ export enum EditorOption {
|
||||
wrappingIndent = 117,
|
||||
wrappingStrategy = 118,
|
||||
showDeprecated = 119,
|
||||
editorClassName = 120,
|
||||
pixelRatio = 121,
|
||||
tabFocusMode = 122,
|
||||
layoutInfo = 123,
|
||||
wrappingInfo = 124
|
||||
inlineHints = 120,
|
||||
editorClassName = 121,
|
||||
pixelRatio = 122,
|
||||
tabFocusMode = 123,
|
||||
layoutInfo = 124,
|
||||
wrappingInfo = 125
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -255,7 +255,7 @@ export class ViewLayout extends Disposable implements IViewLayout {
|
||||
|
||||
let result = this._linesLayout.getLinesTotalHeight();
|
||||
if (options.get(EditorOption.scrollBeyondLastLine)) {
|
||||
result += height - options.get(EditorOption.lineHeight);
|
||||
result += Math.max(0, height - options.get(EditorOption.lineHeight) - options.get(EditorOption.padding).bottom);
|
||||
} else {
|
||||
result += this._getHorizontalScrollbarHeight(width, contentWidth);
|
||||
}
|
||||
|
||||
@@ -303,6 +303,19 @@ function createLineBreaksFromPreviousLineBreaks(classifier: WrappingCharacterCla
|
||||
breakOffsetVisibleColumn = forcedBreakOffsetVisibleColumn;
|
||||
}
|
||||
|
||||
if (breakOffset <= lastBreakingOffset) {
|
||||
// Make sure that we are advancing (at least one character)
|
||||
const charCode = lineText.charCodeAt(lastBreakingOffset);
|
||||
if (strings.isHighSurrogate(charCode)) {
|
||||
// A surrogate pair must always be considered as a single unit, so it is never to be broken
|
||||
breakOffset = lastBreakingOffset + 2;
|
||||
breakOffsetVisibleColumn = lastBreakingOffsetVisibleColumn + 2;
|
||||
} else {
|
||||
breakOffset = lastBreakingOffset + 1;
|
||||
breakOffsetVisibleColumn = lastBreakingOffsetVisibleColumn + computeCharWidth(charCode, lastBreakingOffsetVisibleColumn, tabSize, columnsForFullWidthChar);
|
||||
}
|
||||
}
|
||||
|
||||
lastBreakingOffset = breakOffset;
|
||||
breakingOffsets[breakingOffsetsCount] = breakOffset;
|
||||
lastBreakingOffsetVisibleColumn = breakOffsetVisibleColumn;
|
||||
@@ -435,6 +448,10 @@ function computeCharWidth(charCode: number, visibleColumn: number, tabSize: numb
|
||||
if (strings.isFullWidthCharacter(charCode)) {
|
||||
return columnsForFullWidthChar;
|
||||
}
|
||||
if (charCode < 32) {
|
||||
// when using `editor.renderControlCharacters`, the substitutions are often wide
|
||||
return columnsForFullWidthChar;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
@@ -503,15 +503,8 @@ export class SplitLinesCollection implements IViewModelLinesCollection {
|
||||
return null;
|
||||
}
|
||||
|
||||
let hiddenAreas = this.getHiddenAreas();
|
||||
let isInHiddenArea = false;
|
||||
let testPosition = new Position(fromLineNumber, 1);
|
||||
for (const hiddenArea of hiddenAreas) {
|
||||
if (hiddenArea.containsPosition(testPosition)) {
|
||||
isInHiddenArea = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
// cannot use this.getHiddenAreas() because those decorations have already seen the effect of this model change
|
||||
const isInHiddenArea = (fromLineNumber > 2 && !this.lines[fromLineNumber - 2].isVisible());
|
||||
|
||||
let outputFromLineNumber = (fromLineNumber === 1 ? 1 : this.prefixSumComputer.getAccumulatedValue(fromLineNumber - 2) + 1);
|
||||
|
||||
|
||||
@@ -916,8 +916,8 @@ export class ViewModel extends Disposable implements IViewModel {
|
||||
public getPosition(): Position {
|
||||
return this._cursor.getPrimaryCursorState().modelState.position;
|
||||
}
|
||||
public setSelections(source: string | null | undefined, selections: readonly ISelection[]): void {
|
||||
this._withViewEventsCollector(eventsCollector => this._cursor.setSelections(eventsCollector, source, selections));
|
||||
public setSelections(source: string | null | undefined, selections: readonly ISelection[], reason = CursorChangeReason.NotSet): void {
|
||||
this._withViewEventsCollector(eventsCollector => this._cursor.setSelections(eventsCollector, source, selections, reason));
|
||||
}
|
||||
public saveCursorState(): ICursorState[] {
|
||||
return this._cursor.saveState();
|
||||
|
||||
@@ -39,20 +39,20 @@ suite('bracket matching', () => {
|
||||
// start on closing bracket
|
||||
editor.setPosition(new Position(1, 20));
|
||||
bracketMatchingController.jumpToBracket();
|
||||
assert.deepEqual(editor.getPosition(), new Position(1, 9));
|
||||
assert.deepStrictEqual(editor.getPosition(), new Position(1, 9));
|
||||
bracketMatchingController.jumpToBracket();
|
||||
assert.deepEqual(editor.getPosition(), new Position(1, 19));
|
||||
assert.deepStrictEqual(editor.getPosition(), new Position(1, 19));
|
||||
bracketMatchingController.jumpToBracket();
|
||||
assert.deepEqual(editor.getPosition(), new Position(1, 9));
|
||||
assert.deepStrictEqual(editor.getPosition(), new Position(1, 9));
|
||||
|
||||
// start on opening bracket
|
||||
editor.setPosition(new Position(1, 23));
|
||||
bracketMatchingController.jumpToBracket();
|
||||
assert.deepEqual(editor.getPosition(), new Position(1, 31));
|
||||
assert.deepStrictEqual(editor.getPosition(), new Position(1, 31));
|
||||
bracketMatchingController.jumpToBracket();
|
||||
assert.deepEqual(editor.getPosition(), new Position(1, 23));
|
||||
assert.deepStrictEqual(editor.getPosition(), new Position(1, 23));
|
||||
bracketMatchingController.jumpToBracket();
|
||||
assert.deepEqual(editor.getPosition(), new Position(1, 31));
|
||||
assert.deepStrictEqual(editor.getPosition(), new Position(1, 31));
|
||||
|
||||
bracketMatchingController.dispose();
|
||||
});
|
||||
@@ -71,25 +71,25 @@ suite('bracket matching', () => {
|
||||
// start position between brackets
|
||||
editor.setPosition(new Position(1, 16));
|
||||
bracketMatchingController.jumpToBracket();
|
||||
assert.deepEqual(editor.getPosition(), new Position(1, 18));
|
||||
assert.deepStrictEqual(editor.getPosition(), new Position(1, 18));
|
||||
bracketMatchingController.jumpToBracket();
|
||||
assert.deepEqual(editor.getPosition(), new Position(1, 14));
|
||||
assert.deepStrictEqual(editor.getPosition(), new Position(1, 14));
|
||||
bracketMatchingController.jumpToBracket();
|
||||
assert.deepEqual(editor.getPosition(), new Position(1, 18));
|
||||
assert.deepStrictEqual(editor.getPosition(), new Position(1, 18));
|
||||
|
||||
// skip brackets in comments
|
||||
editor.setPosition(new Position(1, 21));
|
||||
bracketMatchingController.jumpToBracket();
|
||||
assert.deepEqual(editor.getPosition(), new Position(1, 23));
|
||||
assert.deepStrictEqual(editor.getPosition(), new Position(1, 23));
|
||||
bracketMatchingController.jumpToBracket();
|
||||
assert.deepEqual(editor.getPosition(), new Position(1, 24));
|
||||
assert.deepStrictEqual(editor.getPosition(), new Position(1, 24));
|
||||
bracketMatchingController.jumpToBracket();
|
||||
assert.deepEqual(editor.getPosition(), new Position(1, 23));
|
||||
assert.deepStrictEqual(editor.getPosition(), new Position(1, 23));
|
||||
|
||||
// do not break if no brackets are available
|
||||
editor.setPosition(new Position(1, 26));
|
||||
bracketMatchingController.jumpToBracket();
|
||||
assert.deepEqual(editor.getPosition(), new Position(1, 26));
|
||||
assert.deepStrictEqual(editor.getPosition(), new Position(1, 26));
|
||||
|
||||
bracketMatchingController.dispose();
|
||||
});
|
||||
@@ -109,32 +109,32 @@ suite('bracket matching', () => {
|
||||
// start position in open brackets
|
||||
editor.setPosition(new Position(1, 9));
|
||||
bracketMatchingController.selectToBracket(true);
|
||||
assert.deepEqual(editor.getPosition(), new Position(1, 20));
|
||||
assert.deepEqual(editor.getSelection(), new Selection(1, 9, 1, 20));
|
||||
assert.deepStrictEqual(editor.getPosition(), new Position(1, 20));
|
||||
assert.deepStrictEqual(editor.getSelection(), new Selection(1, 9, 1, 20));
|
||||
|
||||
// start position in close brackets
|
||||
editor.setPosition(new Position(1, 20));
|
||||
bracketMatchingController.selectToBracket(true);
|
||||
assert.deepEqual(editor.getPosition(), new Position(1, 20));
|
||||
assert.deepEqual(editor.getSelection(), new Selection(1, 9, 1, 20));
|
||||
assert.deepStrictEqual(editor.getPosition(), new Position(1, 20));
|
||||
assert.deepStrictEqual(editor.getSelection(), new Selection(1, 9, 1, 20));
|
||||
|
||||
// start position between brackets
|
||||
editor.setPosition(new Position(1, 16));
|
||||
bracketMatchingController.selectToBracket(true);
|
||||
assert.deepEqual(editor.getPosition(), new Position(1, 19));
|
||||
assert.deepEqual(editor.getSelection(), new Selection(1, 14, 1, 19));
|
||||
assert.deepStrictEqual(editor.getPosition(), new Position(1, 19));
|
||||
assert.deepStrictEqual(editor.getSelection(), new Selection(1, 14, 1, 19));
|
||||
|
||||
// start position outside brackets
|
||||
editor.setPosition(new Position(1, 21));
|
||||
bracketMatchingController.selectToBracket(true);
|
||||
assert.deepEqual(editor.getPosition(), new Position(1, 25));
|
||||
assert.deepEqual(editor.getSelection(), new Selection(1, 23, 1, 25));
|
||||
assert.deepStrictEqual(editor.getPosition(), new Position(1, 25));
|
||||
assert.deepStrictEqual(editor.getSelection(), new Selection(1, 23, 1, 25));
|
||||
|
||||
// do not break if no brackets are available
|
||||
editor.setPosition(new Position(1, 26));
|
||||
bracketMatchingController.selectToBracket(true);
|
||||
assert.deepEqual(editor.getPosition(), new Position(1, 26));
|
||||
assert.deepEqual(editor.getSelection(), new Selection(1, 26, 1, 26));
|
||||
assert.deepStrictEqual(editor.getPosition(), new Position(1, 26));
|
||||
assert.deepStrictEqual(editor.getSelection(), new Selection(1, 26, 1, 26));
|
||||
|
||||
bracketMatchingController.dispose();
|
||||
});
|
||||
@@ -159,7 +159,7 @@ suite('bracket matching', () => {
|
||||
|
||||
editor.setPosition(new Position(3, 5));
|
||||
bracketMatchingController.jumpToBracket();
|
||||
assert.deepEqual(editor.getSelection(), new Selection(5, 1, 5, 1));
|
||||
assert.deepStrictEqual(editor.getSelection(), new Selection(5, 1, 5, 1));
|
||||
|
||||
bracketMatchingController.dispose();
|
||||
});
|
||||
@@ -184,7 +184,7 @@ suite('bracket matching', () => {
|
||||
|
||||
editor.setPosition(new Position(3, 5));
|
||||
bracketMatchingController.selectToBracket(false);
|
||||
assert.deepEqual(editor.getSelection(), new Selection(1, 12, 5, 1));
|
||||
assert.deepStrictEqual(editor.getSelection(), new Selection(1, 12, 5, 1));
|
||||
|
||||
bracketMatchingController.dispose();
|
||||
});
|
||||
@@ -207,7 +207,7 @@ suite('bracket matching', () => {
|
||||
new Selection(1, 17, 1, 17)
|
||||
]);
|
||||
bracketMatchingController.selectToBracket(true);
|
||||
assert.deepEqual(editor.getSelections(), [
|
||||
assert.deepStrictEqual(editor.getSelections(), [
|
||||
new Selection(1, 1, 1, 5),
|
||||
new Selection(1, 8, 1, 13),
|
||||
new Selection(1, 16, 1, 19)
|
||||
@@ -220,7 +220,7 @@ suite('bracket matching', () => {
|
||||
new Selection(1, 14, 1, 14)
|
||||
]);
|
||||
bracketMatchingController.selectToBracket(true);
|
||||
assert.deepEqual(editor.getSelections(), [
|
||||
assert.deepStrictEqual(editor.getSelections(), [
|
||||
new Selection(1, 1, 1, 5),
|
||||
new Selection(1, 8, 1, 13),
|
||||
new Selection(1, 16, 1, 19)
|
||||
@@ -233,7 +233,7 @@ suite('bracket matching', () => {
|
||||
new Selection(1, 19, 1, 19)
|
||||
]);
|
||||
bracketMatchingController.selectToBracket(true);
|
||||
assert.deepEqual(editor.getSelections(), [
|
||||
assert.deepStrictEqual(editor.getSelections(), [
|
||||
new Selection(1, 1, 1, 5),
|
||||
new Selection(1, 8, 1, 13),
|
||||
new Selection(1, 16, 1, 19)
|
||||
|
||||
@@ -24,10 +24,11 @@ const CLIPBOARD_CONTEXT_MENU_GROUP = '9_cutcopypaste';
|
||||
const supportsCut = (platform.isNative || document.queryCommandSupported('cut'));
|
||||
const supportsCopy = (platform.isNative || document.queryCommandSupported('copy'));
|
||||
// IE and Edge have trouble with setting html content in clipboard
|
||||
const supportsCopyWithSyntaxHighlighting = (supportsCopy && !browser.isEdge);
|
||||
const supportsCopyWithSyntaxHighlighting = (supportsCopy && !browser.isEdgeLegacy);
|
||||
// Firefox only supports navigator.clipboard.readText() in browser extensions.
|
||||
// See https://developer.mozilla.org/en-US/docs/Web/API/Clipboard/readText#Browser_compatibility
|
||||
const supportsPaste = (browser.isFirefox ? document.queryCommandSupported('paste') : true);
|
||||
// When loading over http, navigator.clipboard can be undefined. See https://github.com/microsoft/monaco-editor/issues/2313
|
||||
const supportsPaste = (typeof navigator.clipboard === 'undefined' || browser.isFirefox) ? document.queryCommandSupported('paste') : true;
|
||||
|
||||
function registerCommand<T extends Command>(command: T): T {
|
||||
command.register();
|
||||
|
||||
@@ -98,14 +98,17 @@ export class CodeLensContribution implements IEditorContribution {
|
||||
const fontFamily = this._editor.getOption(EditorOption.codeLensFontFamily);
|
||||
const editorFontInfo = this._editor.getOption(EditorOption.fontInfo);
|
||||
|
||||
const fontFamilyVar = `--codelens-font-family${this._styleClassName}`;
|
||||
|
||||
let newStyle = `
|
||||
.monaco-editor .codelens-decoration.${this._styleClassName} { line-height: ${codeLensHeight}px; font-size: ${fontSize}px; padding-right: ${Math.round(fontSize * 0.5)}px; font-feature-settings: ${editorFontInfo.fontFeatureSettings} }
|
||||
.monaco-editor .codelens-decoration.${this._styleClassName} span.codicon { line-height: ${codeLensHeight}px; font-size: ${fontSize}px; }
|
||||
`;
|
||||
if (fontFamily) {
|
||||
newStyle += `.monaco-editor .codelens-decoration.${this._styleClassName} { font-family: '${fontFamily}'}`;
|
||||
newStyle += `.monaco-editor .codelens-decoration.${this._styleClassName} { font-family: var(${fontFamilyVar})}`;
|
||||
}
|
||||
this._styleElement.textContent = newStyle;
|
||||
this._editor.getDomNode()?.style.setProperty(fontFamilyVar, fontFamily ?? 'inherit');
|
||||
|
||||
//
|
||||
this._editor.changeViewZones(accessor => {
|
||||
|
||||
@@ -14,7 +14,7 @@ import { editorCodeLensForeground } from 'vs/editor/common/view/editorColorRegis
|
||||
import { CodeLensItem } from 'vs/editor/contrib/codelens/codelens';
|
||||
import { editorActiveLinkForeground } from 'vs/platform/theme/common/colorRegistry';
|
||||
import { registerThemingParticipant } from 'vs/platform/theme/common/themeService';
|
||||
import { renderCodicons } from 'vs/base/browser/codicons';
|
||||
import { renderLabelWithIcons } from 'vs/base/browser/ui/iconLabel/iconLabels';
|
||||
|
||||
class CodeLensViewZone implements IViewZone {
|
||||
|
||||
@@ -88,7 +88,7 @@ class CodeLensContentWidget implements IContentWidget {
|
||||
}
|
||||
hasSymbol = true;
|
||||
if (lens.command) {
|
||||
const title = renderCodicons(lens.command.title.trim());
|
||||
const title = renderLabelWithIcons(lens.command.title.trim());
|
||||
if (lens.command.id) {
|
||||
children.push(dom.$('a', { id: String(i) }, ...title));
|
||||
this._commands.set(String(i), lens.command);
|
||||
|
||||
@@ -47,7 +47,7 @@ export class ColorContribution extends Disposable implements IEditorContribution
|
||||
}
|
||||
|
||||
const hoverController = this._editor.getContribution<ModesHoverController>(ModesHoverController.ID);
|
||||
if (!hoverController.contentWidget.isColorPickerVisible()) {
|
||||
if (!hoverController.isColorPickerVisible()) {
|
||||
const range = new Range(mouseEvent.target.range.startLineNumber, mouseEvent.target.range.startColumn + 1, mouseEvent.target.range.endLineNumber, mouseEvent.target.range.endColumn + 1);
|
||||
hoverController.showContentHover(range, HoverStartMode.Delayed, false);
|
||||
}
|
||||
|
||||
@@ -96,25 +96,25 @@ suite('Editor Contrib - Line Comment Command', () => {
|
||||
throw new Error(`unexpected`);
|
||||
}
|
||||
|
||||
assert.equal(r.shouldRemoveComments, false);
|
||||
assert.strictEqual(r.shouldRemoveComments, false);
|
||||
|
||||
// Does not change `commentStr`
|
||||
assert.equal(r.lines[0].commentStr, '//');
|
||||
assert.equal(r.lines[1].commentStr, 'rem');
|
||||
assert.equal(r.lines[2].commentStr, '!@#');
|
||||
assert.equal(r.lines[3].commentStr, '!@#');
|
||||
assert.strictEqual(r.lines[0].commentStr, '//');
|
||||
assert.strictEqual(r.lines[1].commentStr, 'rem');
|
||||
assert.strictEqual(r.lines[2].commentStr, '!@#');
|
||||
assert.strictEqual(r.lines[3].commentStr, '!@#');
|
||||
|
||||
// Fills in `isWhitespace`
|
||||
assert.equal(r.lines[0].ignore, true);
|
||||
assert.equal(r.lines[1].ignore, true);
|
||||
assert.equal(r.lines[2].ignore, false);
|
||||
assert.equal(r.lines[3].ignore, false);
|
||||
assert.strictEqual(r.lines[0].ignore, true);
|
||||
assert.strictEqual(r.lines[1].ignore, true);
|
||||
assert.strictEqual(r.lines[2].ignore, false);
|
||||
assert.strictEqual(r.lines[3].ignore, false);
|
||||
|
||||
// Fills in `commentStrOffset`
|
||||
assert.equal(r.lines[0].commentStrOffset, 2);
|
||||
assert.equal(r.lines[1].commentStrOffset, 4);
|
||||
assert.equal(r.lines[2].commentStrOffset, 4);
|
||||
assert.equal(r.lines[3].commentStrOffset, 2);
|
||||
assert.strictEqual(r.lines[0].commentStrOffset, 2);
|
||||
assert.strictEqual(r.lines[1].commentStrOffset, 4);
|
||||
assert.strictEqual(r.lines[2].commentStrOffset, 4);
|
||||
assert.strictEqual(r.lines[3].commentStrOffset, 2);
|
||||
|
||||
|
||||
r = LineCommentCommand._analyzeLines(Type.Toggle, true, createSimpleModel([
|
||||
@@ -127,31 +127,31 @@ suite('Editor Contrib - Line Comment Command', () => {
|
||||
throw new Error(`unexpected`);
|
||||
}
|
||||
|
||||
assert.equal(r.shouldRemoveComments, true);
|
||||
assert.strictEqual(r.shouldRemoveComments, true);
|
||||
|
||||
// Does not change `commentStr`
|
||||
assert.equal(r.lines[0].commentStr, '//');
|
||||
assert.equal(r.lines[1].commentStr, 'rem');
|
||||
assert.equal(r.lines[2].commentStr, '!@#');
|
||||
assert.equal(r.lines[3].commentStr, '!@#');
|
||||
assert.strictEqual(r.lines[0].commentStr, '//');
|
||||
assert.strictEqual(r.lines[1].commentStr, 'rem');
|
||||
assert.strictEqual(r.lines[2].commentStr, '!@#');
|
||||
assert.strictEqual(r.lines[3].commentStr, '!@#');
|
||||
|
||||
// Fills in `isWhitespace`
|
||||
assert.equal(r.lines[0].ignore, true);
|
||||
assert.equal(r.lines[1].ignore, false);
|
||||
assert.equal(r.lines[2].ignore, false);
|
||||
assert.equal(r.lines[3].ignore, false);
|
||||
assert.strictEqual(r.lines[0].ignore, true);
|
||||
assert.strictEqual(r.lines[1].ignore, false);
|
||||
assert.strictEqual(r.lines[2].ignore, false);
|
||||
assert.strictEqual(r.lines[3].ignore, false);
|
||||
|
||||
// Fills in `commentStrOffset`
|
||||
assert.equal(r.lines[0].commentStrOffset, 2);
|
||||
assert.equal(r.lines[1].commentStrOffset, 4);
|
||||
assert.equal(r.lines[2].commentStrOffset, 4);
|
||||
assert.equal(r.lines[3].commentStrOffset, 2);
|
||||
assert.strictEqual(r.lines[0].commentStrOffset, 2);
|
||||
assert.strictEqual(r.lines[1].commentStrOffset, 4);
|
||||
assert.strictEqual(r.lines[2].commentStrOffset, 4);
|
||||
assert.strictEqual(r.lines[3].commentStrOffset, 2);
|
||||
|
||||
// Fills in `commentStrLength`
|
||||
assert.equal(r.lines[0].commentStrLength, 2);
|
||||
assert.equal(r.lines[1].commentStrLength, 4);
|
||||
assert.equal(r.lines[2].commentStrLength, 4);
|
||||
assert.equal(r.lines[3].commentStrLength, 3);
|
||||
assert.strictEqual(r.lines[0].commentStrLength, 2);
|
||||
assert.strictEqual(r.lines[1].commentStrLength, 4);
|
||||
assert.strictEqual(r.lines[2].commentStrLength, 4);
|
||||
assert.strictEqual(r.lines[3].commentStrLength, 3);
|
||||
});
|
||||
|
||||
test('_normalizeInsertionPoint', () => {
|
||||
@@ -166,7 +166,7 @@ suite('Editor Contrib - Line Comment Command', () => {
|
||||
});
|
||||
LineCommentCommand._normalizeInsertionPoint(model, offsets, 1, tabSize);
|
||||
const actual = offsets.map(item => item.commentStrOffset);
|
||||
assert.deepEqual(actual, expected, testName);
|
||||
assert.deepStrictEqual(actual, expected, testName);
|
||||
};
|
||||
|
||||
// Bug 16696:[comment] comments not aligned in this case
|
||||
@@ -1083,7 +1083,7 @@ suite('Editor Contrib - Line Comment in mixed modes', () => {
|
||||
tokenize: () => {
|
||||
throw new Error('not implemented');
|
||||
},
|
||||
tokenize2: (line: string, state: modes.IState): TokenizationResult2 => {
|
||||
tokenize2: (line: string, hasEOL: boolean, state: modes.IState): TokenizationResult2 => {
|
||||
let languageId = (/^ /.test(line) ? INNER_LANGUAGE_ID : OUTER_LANGUAGE_ID);
|
||||
|
||||
let tokens = new Uint32Array(1 << 1);
|
||||
|
||||
@@ -29,16 +29,16 @@ suite('FindController', () => {
|
||||
|
||||
// press Delete
|
||||
CoreEditingCommands.DeleteRight.runEditorCommand(null, editor, {});
|
||||
assert.deepEqual(editor.getValue(), 'hell');
|
||||
assert.deepEqual(editor.getSelections(), [new Selection(1, 5, 1, 5)]);
|
||||
assert.deepStrictEqual(editor.getValue(), 'hell');
|
||||
assert.deepStrictEqual(editor.getSelections(), [new Selection(1, 5, 1, 5)]);
|
||||
|
||||
// press left
|
||||
CoreNavigationCommands.CursorLeft.runEditorCommand(null, editor, {});
|
||||
assert.deepEqual(editor.getSelections(), [new Selection(1, 4, 1, 4)]);
|
||||
assert.deepStrictEqual(editor.getSelections(), [new Selection(1, 4, 1, 4)]);
|
||||
|
||||
// press Ctrl+U
|
||||
cursorUndoAction.run(null!, editor, {});
|
||||
assert.deepEqual(editor.getSelections(), [new Selection(1, 5, 1, 5)]);
|
||||
assert.deepStrictEqual(editor.getSelections(), [new Selection(1, 5, 1, 5)]);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -52,12 +52,12 @@ suite('FindController', () => {
|
||||
// type hello
|
||||
editor.trigger('test', Handler.Type, { text: 'hell' });
|
||||
editor.trigger('test', Handler.Type, { text: 'o' });
|
||||
assert.deepEqual(editor.getValue(), 'hello');
|
||||
assert.deepEqual(editor.getSelections(), [new Selection(1, 6, 1, 6)]);
|
||||
assert.deepStrictEqual(editor.getValue(), 'hello');
|
||||
assert.deepStrictEqual(editor.getSelections(), [new Selection(1, 6, 1, 6)]);
|
||||
|
||||
// press Ctrl+U
|
||||
cursorUndoAction.run(null!, editor, {});
|
||||
assert.deepEqual(editor.getSelections(), [new Selection(1, 6, 1, 6)]);
|
||||
assert.deepStrictEqual(editor.getSelections(), [new Selection(1, 6, 1, 6)]);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -20,6 +20,7 @@ import { IModelDeltaDecoration } from 'vs/editor/common/model';
|
||||
import { IMouseEvent } from 'vs/base/browser/mouseEvent';
|
||||
import { CodeEditorWidget } from 'vs/editor/browser/widget/codeEditorWidget';
|
||||
import { EditorOption } from 'vs/editor/common/config/editorOptions';
|
||||
import { CursorChangeReason } from 'vs/editor/common/controller/cursorEvents';
|
||||
|
||||
function hasTriggerModifier(e: IKeyboardEvent | IMouseEvent): boolean {
|
||||
if (isMacintosh) {
|
||||
@@ -176,8 +177,8 @@ export class DragAndDropController extends Disposable implements IEditorContribu
|
||||
}
|
||||
});
|
||||
}
|
||||
// Use `mouse` as the source instead of `api`.
|
||||
(<CodeEditorWidget>this._editor).setSelections(newSelections || [], 'mouse');
|
||||
// Use `mouse` as the source instead of `api` and setting the reason to explicit (to behave like any other mouse operation).
|
||||
(<CodeEditorWidget>this._editor).setSelections(newSelections || [], 'mouse', CursorChangeReason.Explicit);
|
||||
} else if (!this._dragSelection.containsPosition(newCursorPosition) ||
|
||||
(
|
||||
(
|
||||
|
||||
@@ -4,62 +4,20 @@
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { URI } from 'vs/base/common/uri';
|
||||
import { Range } from 'vs/editor/common/core/range';
|
||||
import { ITextModel } from 'vs/editor/common/model';
|
||||
import { DocumentSymbol } from 'vs/editor/common/modes';
|
||||
import { IModelService } from 'vs/editor/common/services/modelService';
|
||||
import { CancellationToken } from 'vs/base/common/cancellation';
|
||||
import { ITextModelService } from 'vs/editor/common/services/resolverService';
|
||||
import { OutlineModel, OutlineElement } from 'vs/editor/contrib/documentSymbols/outlineModel';
|
||||
import { OutlineModel } from 'vs/editor/contrib/documentSymbols/outlineModel';
|
||||
import { CommandsRegistry } from 'vs/platform/commands/common/commands';
|
||||
import { assertType } from 'vs/base/common/types';
|
||||
import { Iterable } from 'vs/base/common/iterator';
|
||||
|
||||
export async function getDocumentSymbols(document: ITextModel, flat: boolean, token: CancellationToken): Promise<DocumentSymbol[]> {
|
||||
|
||||
const model = await OutlineModel.create(document, token);
|
||||
const roots: DocumentSymbol[] = [];
|
||||
for (const child of model.children.values()) {
|
||||
if (child instanceof OutlineElement) {
|
||||
roots.push(child.symbol);
|
||||
} else {
|
||||
roots.push(...Iterable.map(child.children.values(), child => child.symbol));
|
||||
}
|
||||
}
|
||||
|
||||
let flatEntries: DocumentSymbol[] = [];
|
||||
if (token.isCancellationRequested) {
|
||||
return flatEntries;
|
||||
}
|
||||
if (flat) {
|
||||
flatten(flatEntries, roots, '');
|
||||
} else {
|
||||
flatEntries = roots;
|
||||
}
|
||||
|
||||
return flatEntries.sort(compareEntriesUsingStart);
|
||||
}
|
||||
|
||||
function compareEntriesUsingStart(a: DocumentSymbol, b: DocumentSymbol): number {
|
||||
return Range.compareRangesUsingStarts(a.range, b.range);
|
||||
}
|
||||
|
||||
function flatten(bucket: DocumentSymbol[], entries: DocumentSymbol[], overrideContainerLabel: string): void {
|
||||
for (let entry of entries) {
|
||||
bucket.push({
|
||||
kind: entry.kind,
|
||||
tags: entry.tags,
|
||||
name: entry.name,
|
||||
detail: entry.detail,
|
||||
containerName: entry.containerName || overrideContainerLabel,
|
||||
range: entry.range,
|
||||
selectionRange: entry.selectionRange,
|
||||
children: undefined, // we flatten it...
|
||||
});
|
||||
if (entry.children) {
|
||||
flatten(bucket, entry.children, entry.name);
|
||||
}
|
||||
}
|
||||
return flat
|
||||
? model.asListOfDocumentSymbols()
|
||||
: model.getTopLevelSymbols();
|
||||
}
|
||||
|
||||
CommandsRegistry.registerCommand('_executeDocumentSymbolProvider', async function (accessor, ...args) {
|
||||
@@ -1,46 +0,0 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
.monaco-list .monaco-list-row.focused.selected .outline-element .monaco-highlighted-label,
|
||||
.monaco-list .monaco-list-row.focused.selected .outline-element-decoration {
|
||||
/* make sure selection color wins when a label is being selected */
|
||||
color: inherit !important;
|
||||
}
|
||||
|
||||
.monaco-list .outline-element {
|
||||
display: flex;
|
||||
flex: 1;
|
||||
flex-flow: row nowrap;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.monaco-list .outline-element .monaco-highlighted-label {
|
||||
color: var(--outline-element-color);
|
||||
}
|
||||
|
||||
.monaco-list .outline-element .monaco-icon-label-container .monaco-highlighted-label,
|
||||
.monaco-list .outline-element .monaco-icon-label-container .label-description {
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.monaco-list .outline-element .outline-element-decoration {
|
||||
opacity: 0.75;
|
||||
font-size: 90%;
|
||||
font-weight: 600;
|
||||
padding: 0 12px 0 5px;
|
||||
margin-left: auto;
|
||||
text-align: center;
|
||||
color: var(--outline-element-color);
|
||||
}
|
||||
|
||||
.monaco-list .outline-element .outline-element-decoration.bubble {
|
||||
font-family: codicon;
|
||||
font-size: 14px;
|
||||
opacity: 0.4;
|
||||
}
|
||||
|
||||
.monaco-list .outline-element .outline-element-icon {
|
||||
margin-right: 4px;
|
||||
}
|
||||
@@ -1,9 +0,0 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
.monaco-icon-label.deprecated {
|
||||
text-decoration: line-through;
|
||||
opacity: 0.66;
|
||||
}
|
||||
@@ -1,18 +0,0 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { RawContextKey } from 'vs/platform/contextkey/common/contextkey';
|
||||
|
||||
export const OutlineViewId = 'outline';
|
||||
|
||||
export const OutlineViewFiltered = new RawContextKey('outlineFiltered', false);
|
||||
export const OutlineViewFocused = new RawContextKey('outlineFocused', false);
|
||||
|
||||
export const enum OutlineConfigKeys {
|
||||
'icons' = 'outline.icons',
|
||||
'problemsEnabled' = 'outline.problems.enabled',
|
||||
'problemsColors' = 'outline.problems.colors',
|
||||
'problemsBadges' = 'outline.problems.badges'
|
||||
}
|
||||
@@ -14,8 +14,8 @@ import { ITextModel } from 'vs/editor/common/model';
|
||||
import { DocumentSymbol, DocumentSymbolProvider, DocumentSymbolProviderRegistry } from 'vs/editor/common/modes';
|
||||
import { MarkerSeverity } from 'vs/platform/markers/common/markers';
|
||||
import { Iterable } from 'vs/base/common/iterator';
|
||||
import { URI } from 'vs/base/common/uri';
|
||||
import { LanguageFeatureRequestDelays } from 'vs/editor/common/modes/languageFeatureRegistry';
|
||||
import { URI } from 'vs/base/common/uri';
|
||||
|
||||
export abstract class TreeElement {
|
||||
|
||||
@@ -204,8 +204,6 @@ export class OutlineGroup extends TreeElement {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
export class OutlineModel extends TreeElement {
|
||||
|
||||
private static readonly _requestDurations = new LanguageFeatureRequestDelays(DocumentSymbolProviderRegistry, 350);
|
||||
@@ -445,4 +443,43 @@ export class OutlineModel extends TreeElement {
|
||||
group.updateMarker(marker.slice(0));
|
||||
}
|
||||
}
|
||||
|
||||
getTopLevelSymbols(): DocumentSymbol[] {
|
||||
const roots: DocumentSymbol[] = [];
|
||||
for (const child of this.children.values()) {
|
||||
if (child instanceof OutlineElement) {
|
||||
roots.push(child.symbol);
|
||||
} else {
|
||||
roots.push(...Iterable.map(child.children.values(), child => child.symbol));
|
||||
}
|
||||
}
|
||||
return roots.sort((a, b) => Range.compareRangesUsingStarts(a.range, b.range));
|
||||
}
|
||||
|
||||
asListOfDocumentSymbols(): DocumentSymbol[] {
|
||||
const roots = this.getTopLevelSymbols();
|
||||
const bucket: DocumentSymbol[] = [];
|
||||
OutlineModel._flattenDocumentSymbols(bucket, roots, '');
|
||||
return bucket.sort((a, b) => Range.compareRangesUsingStarts(a.range, b.range));
|
||||
}
|
||||
|
||||
private static _flattenDocumentSymbols(bucket: DocumentSymbol[], entries: DocumentSymbol[], overrideContainerLabel: string): void {
|
||||
for (const entry of entries) {
|
||||
bucket.push({
|
||||
kind: entry.kind,
|
||||
tags: entry.tags,
|
||||
name: entry.name,
|
||||
detail: entry.detail,
|
||||
containerName: entry.containerName || overrideContainerLabel,
|
||||
range: entry.range,
|
||||
selectionRange: entry.selectionRange,
|
||||
children: undefined, // we flatten it...
|
||||
});
|
||||
|
||||
// Recurse over children
|
||||
if (entry.children) {
|
||||
OutlineModel._flattenDocumentSymbols(bucket, entry.children, entry.name);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,725 +0,0 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import * as dom from 'vs/base/browser/dom';
|
||||
import { HighlightedLabel } from 'vs/base/browser/ui/highlightedlabel/highlightedLabel';
|
||||
import { IIdentityProvider, IKeyboardNavigationLabelProvider, IListVirtualDelegate } from 'vs/base/browser/ui/list/list';
|
||||
import { IDataSource, ITreeNode, ITreeRenderer, ITreeSorter, ITreeFilter } from 'vs/base/browser/ui/tree/tree';
|
||||
import { createMatches, FuzzyScore } from 'vs/base/common/filters';
|
||||
import 'vs/css!./media/outlineTree';
|
||||
import 'vs/css!./media/symbol-icons';
|
||||
import { Range } from 'vs/editor/common/core/range';
|
||||
import { SymbolKind, SymbolKinds, SymbolTag } from 'vs/editor/common/modes';
|
||||
import { OutlineElement, OutlineGroup, OutlineModel } from 'vs/editor/contrib/documentSymbols/outlineModel';
|
||||
import { localize } from 'vs/nls';
|
||||
import { IconLabel } from 'vs/base/browser/ui/iconLabel/iconLabel';
|
||||
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
|
||||
import { OutlineConfigKeys } from 'vs/editor/contrib/documentSymbols/outline';
|
||||
import { MarkerSeverity } from 'vs/platform/markers/common/markers';
|
||||
import { IThemeService, registerThemingParticipant, IColorTheme, ICssStyleCollector } from 'vs/platform/theme/common/themeService';
|
||||
import { registerColor, listErrorForeground, listWarningForeground, foreground } from 'vs/platform/theme/common/colorRegistry';
|
||||
import { IdleValue } from 'vs/base/common/async';
|
||||
import { ITextResourceConfigurationService } from 'vs/editor/common/services/textResourceConfigurationService';
|
||||
import { URI } from 'vs/base/common/uri';
|
||||
import { IListAccessibilityProvider } from 'vs/base/browser/ui/list/listWidget';
|
||||
import { Iterable } from 'vs/base/common/iterator';
|
||||
import { Codicon } from 'vs/base/common/codicons';
|
||||
|
||||
export type OutlineItem = OutlineGroup | OutlineElement;
|
||||
|
||||
export class OutlineNavigationLabelProvider implements IKeyboardNavigationLabelProvider<OutlineItem> {
|
||||
|
||||
getKeyboardNavigationLabel(element: OutlineItem): { toString(): string; } {
|
||||
if (element instanceof OutlineGroup) {
|
||||
return element.label;
|
||||
} else {
|
||||
return element.symbol.name;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export class OutlineAccessibilityProvider implements IListAccessibilityProvider<OutlineItem> {
|
||||
|
||||
constructor(private readonly ariaLabel: string) { }
|
||||
|
||||
getWidgetAriaLabel(): string {
|
||||
return this.ariaLabel;
|
||||
}
|
||||
|
||||
getAriaLabel(element: OutlineItem): string | null {
|
||||
if (element instanceof OutlineGroup) {
|
||||
return element.label;
|
||||
} else {
|
||||
return element.symbol.name;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export class OutlineIdentityProvider implements IIdentityProvider<OutlineItem> {
|
||||
getId(element: OutlineItem): { toString(): string; } {
|
||||
return element.id;
|
||||
}
|
||||
}
|
||||
|
||||
export class OutlineGroupTemplate {
|
||||
static readonly id = 'OutlineGroupTemplate';
|
||||
constructor(
|
||||
readonly labelContainer: HTMLElement,
|
||||
readonly label: HighlightedLabel,
|
||||
) { }
|
||||
}
|
||||
|
||||
export class OutlineElementTemplate {
|
||||
static readonly id = 'OutlineElementTemplate';
|
||||
constructor(
|
||||
readonly container: HTMLElement,
|
||||
readonly iconLabel: IconLabel,
|
||||
readonly iconClass: HTMLElement,
|
||||
readonly decoration: HTMLElement,
|
||||
) { }
|
||||
}
|
||||
|
||||
export class OutlineVirtualDelegate implements IListVirtualDelegate<OutlineItem> {
|
||||
|
||||
getHeight(_element: OutlineItem): number {
|
||||
return 22;
|
||||
}
|
||||
|
||||
getTemplateId(element: OutlineItem): string {
|
||||
if (element instanceof OutlineGroup) {
|
||||
return OutlineGroupTemplate.id;
|
||||
} else {
|
||||
return OutlineElementTemplate.id;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export class OutlineGroupRenderer implements ITreeRenderer<OutlineGroup, FuzzyScore, OutlineGroupTemplate> {
|
||||
|
||||
readonly templateId: string = OutlineGroupTemplate.id;
|
||||
|
||||
renderTemplate(container: HTMLElement): OutlineGroupTemplate {
|
||||
const labelContainer = dom.$('.outline-element-label');
|
||||
container.classList.add('outline-element');
|
||||
dom.append(container, labelContainer);
|
||||
return new OutlineGroupTemplate(labelContainer, new HighlightedLabel(labelContainer, true));
|
||||
}
|
||||
|
||||
renderElement(node: ITreeNode<OutlineGroup, FuzzyScore>, index: number, template: OutlineGroupTemplate): void {
|
||||
template.label.set(
|
||||
node.element.label,
|
||||
createMatches(node.filterData)
|
||||
);
|
||||
}
|
||||
|
||||
disposeTemplate(_template: OutlineGroupTemplate): void {
|
||||
// nothing
|
||||
}
|
||||
}
|
||||
|
||||
export class OutlineElementRenderer implements ITreeRenderer<OutlineElement, FuzzyScore, OutlineElementTemplate> {
|
||||
|
||||
readonly templateId: string = OutlineElementTemplate.id;
|
||||
|
||||
constructor(
|
||||
@IConfigurationService private readonly _configurationService: IConfigurationService,
|
||||
@IThemeService private readonly _themeService: IThemeService,
|
||||
) { }
|
||||
|
||||
renderTemplate(container: HTMLElement): OutlineElementTemplate {
|
||||
container.classList.add('outline-element');
|
||||
const iconLabel = new IconLabel(container, { supportHighlights: true });
|
||||
const iconClass = dom.$('.outline-element-icon');
|
||||
const decoration = dom.$('.outline-element-decoration');
|
||||
container.prepend(iconClass);
|
||||
container.appendChild(decoration);
|
||||
return new OutlineElementTemplate(container, iconLabel, iconClass, decoration);
|
||||
}
|
||||
|
||||
renderElement(node: ITreeNode<OutlineElement, FuzzyScore>, index: number, template: OutlineElementTemplate): void {
|
||||
const { element } = node;
|
||||
const options = {
|
||||
matches: createMatches(node.filterData),
|
||||
labelEscapeNewLines: true,
|
||||
extraClasses: <string[]>[],
|
||||
title: localize('title.template', "{0} ({1})", element.symbol.name, OutlineElementRenderer._symbolKindNames[element.symbol.kind])
|
||||
};
|
||||
if (this._configurationService.getValue(OutlineConfigKeys.icons)) {
|
||||
// add styles for the icons
|
||||
template.iconClass.className = '';
|
||||
template.iconClass.classList.add(`outline-element-icon`, ...SymbolKinds.toCssClassName(element.symbol.kind, true).split(' '));
|
||||
}
|
||||
if (element.symbol.tags.indexOf(SymbolTag.Deprecated) >= 0) {
|
||||
options.extraClasses.push(`deprecated`);
|
||||
options.matches = [];
|
||||
}
|
||||
template.iconLabel.setLabel(element.symbol.name, element.symbol.detail, options);
|
||||
this._renderMarkerInfo(element, template);
|
||||
}
|
||||
|
||||
private _renderMarkerInfo(element: OutlineElement, template: OutlineElementTemplate): void {
|
||||
|
||||
if (!element.marker) {
|
||||
dom.hide(template.decoration);
|
||||
template.container.style.removeProperty('--outline-element-color');
|
||||
return;
|
||||
}
|
||||
|
||||
const { count, topSev } = element.marker;
|
||||
const color = this._themeService.getColorTheme().getColor(topSev === MarkerSeverity.Error ? listErrorForeground : listWarningForeground);
|
||||
const cssColor = color ? color.toString() : 'inherit';
|
||||
|
||||
// color of the label
|
||||
if (this._configurationService.getValue(OutlineConfigKeys.problemsColors)) {
|
||||
template.container.style.setProperty('--outline-element-color', cssColor);
|
||||
} else {
|
||||
template.container.style.removeProperty('--outline-element-color');
|
||||
}
|
||||
|
||||
// badge with color/rollup
|
||||
if (!this._configurationService.getValue(OutlineConfigKeys.problemsBadges)) {
|
||||
dom.hide(template.decoration);
|
||||
|
||||
} else if (count > 0) {
|
||||
dom.show(template.decoration);
|
||||
template.decoration.classList.remove('bubble');
|
||||
template.decoration.innerText = count < 10 ? count.toString() : '+9';
|
||||
template.decoration.title = count === 1 ? localize('1.problem', "1 problem in this element") : localize('N.problem', "{0} problems in this element", count);
|
||||
template.decoration.style.setProperty('--outline-element-color', cssColor);
|
||||
|
||||
} else {
|
||||
dom.show(template.decoration);
|
||||
template.decoration.classList.add('bubble');
|
||||
template.decoration.innerText = '\uea71';
|
||||
template.decoration.title = localize('deep.problem', "Contains elements with problems");
|
||||
template.decoration.style.setProperty('--outline-element-color', cssColor);
|
||||
}
|
||||
}
|
||||
|
||||
private static _symbolKindNames: { [symbol: number]: string } = {
|
||||
[SymbolKind.Array]: localize('Array', "array"),
|
||||
[SymbolKind.Boolean]: localize('Boolean', "boolean"),
|
||||
[SymbolKind.Class]: localize('Class', "class"),
|
||||
[SymbolKind.Constant]: localize('Constant', "constant"),
|
||||
[SymbolKind.Constructor]: localize('Constructor', "constructor"),
|
||||
[SymbolKind.Enum]: localize('Enum', "enumeration"),
|
||||
[SymbolKind.EnumMember]: localize('EnumMember', "enumeration member"),
|
||||
[SymbolKind.Event]: localize('Event', "event"),
|
||||
[SymbolKind.Field]: localize('Field', "field"),
|
||||
[SymbolKind.File]: localize('File', "file"),
|
||||
[SymbolKind.Function]: localize('Function', "function"),
|
||||
[SymbolKind.Interface]: localize('Interface', "interface"),
|
||||
[SymbolKind.Key]: localize('Key', "key"),
|
||||
[SymbolKind.Method]: localize('Method', "method"),
|
||||
[SymbolKind.Module]: localize('Module', "module"),
|
||||
[SymbolKind.Namespace]: localize('Namespace', "namespace"),
|
||||
[SymbolKind.Null]: localize('Null', "null"),
|
||||
[SymbolKind.Number]: localize('Number', "number"),
|
||||
[SymbolKind.Object]: localize('Object', "object"),
|
||||
[SymbolKind.Operator]: localize('Operator', "operator"),
|
||||
[SymbolKind.Package]: localize('Package', "package"),
|
||||
[SymbolKind.Property]: localize('Property', "property"),
|
||||
[SymbolKind.String]: localize('String', "string"),
|
||||
[SymbolKind.Struct]: localize('Struct', "struct"),
|
||||
[SymbolKind.TypeParameter]: localize('TypeParameter', "type parameter"),
|
||||
[SymbolKind.Variable]: localize('Variable', "variable"),
|
||||
};
|
||||
|
||||
disposeTemplate(_template: OutlineElementTemplate): void {
|
||||
_template.iconLabel.dispose();
|
||||
}
|
||||
}
|
||||
|
||||
export const enum OutlineSortOrder {
|
||||
ByPosition,
|
||||
ByName,
|
||||
ByKind
|
||||
}
|
||||
|
||||
export class OutlineFilter implements ITreeFilter<OutlineItem> {
|
||||
|
||||
static readonly configNameToKind = Object.freeze({
|
||||
['showFiles']: SymbolKind.File,
|
||||
['showModules']: SymbolKind.Module,
|
||||
['showNamespaces']: SymbolKind.Namespace,
|
||||
['showPackages']: SymbolKind.Package,
|
||||
['showClasses']: SymbolKind.Class,
|
||||
['showMethods']: SymbolKind.Method,
|
||||
['showProperties']: SymbolKind.Property,
|
||||
['showFields']: SymbolKind.Field,
|
||||
['showConstructors']: SymbolKind.Constructor,
|
||||
['showEnums']: SymbolKind.Enum,
|
||||
['showInterfaces']: SymbolKind.Interface,
|
||||
['showFunctions']: SymbolKind.Function,
|
||||
['showVariables']: SymbolKind.Variable,
|
||||
['showConstants']: SymbolKind.Constant,
|
||||
['showStrings']: SymbolKind.String,
|
||||
['showNumbers']: SymbolKind.Number,
|
||||
['showBooleans']: SymbolKind.Boolean,
|
||||
['showArrays']: SymbolKind.Array,
|
||||
['showObjects']: SymbolKind.Object,
|
||||
['showKeys']: SymbolKind.Key,
|
||||
['showNull']: SymbolKind.Null,
|
||||
['showEnumMembers']: SymbolKind.EnumMember,
|
||||
['showStructs']: SymbolKind.Struct,
|
||||
['showEvents']: SymbolKind.Event,
|
||||
['showOperators']: SymbolKind.Operator,
|
||||
['showTypeParameters']: SymbolKind.TypeParameter,
|
||||
});
|
||||
|
||||
static readonly kindToConfigName = Object.freeze({
|
||||
[SymbolKind.File]: 'showFiles',
|
||||
[SymbolKind.Module]: 'showModules',
|
||||
[SymbolKind.Namespace]: 'showNamespaces',
|
||||
[SymbolKind.Package]: 'showPackages',
|
||||
[SymbolKind.Class]: 'showClasses',
|
||||
[SymbolKind.Method]: 'showMethods',
|
||||
[SymbolKind.Property]: 'showProperties',
|
||||
[SymbolKind.Field]: 'showFields',
|
||||
[SymbolKind.Constructor]: 'showConstructors',
|
||||
[SymbolKind.Enum]: 'showEnums',
|
||||
[SymbolKind.Interface]: 'showInterfaces',
|
||||
[SymbolKind.Function]: 'showFunctions',
|
||||
[SymbolKind.Variable]: 'showVariables',
|
||||
[SymbolKind.Constant]: 'showConstants',
|
||||
[SymbolKind.String]: 'showStrings',
|
||||
[SymbolKind.Number]: 'showNumbers',
|
||||
[SymbolKind.Boolean]: 'showBooleans',
|
||||
[SymbolKind.Array]: 'showArrays',
|
||||
[SymbolKind.Object]: 'showObjects',
|
||||
[SymbolKind.Key]: 'showKeys',
|
||||
[SymbolKind.Null]: 'showNull',
|
||||
[SymbolKind.EnumMember]: 'showEnumMembers',
|
||||
[SymbolKind.Struct]: 'showStructs',
|
||||
[SymbolKind.Event]: 'showEvents',
|
||||
[SymbolKind.Operator]: 'showOperators',
|
||||
[SymbolKind.TypeParameter]: 'showTypeParameters',
|
||||
});
|
||||
|
||||
constructor(
|
||||
private readonly _prefix: string,
|
||||
@ITextResourceConfigurationService private readonly _textResourceConfigService: ITextResourceConfigurationService,
|
||||
) { }
|
||||
|
||||
filter(element: OutlineItem): boolean {
|
||||
const outline = OutlineModel.get(element);
|
||||
let uri: URI | undefined;
|
||||
|
||||
if (outline) {
|
||||
uri = outline.uri;
|
||||
}
|
||||
|
||||
if (!(element instanceof OutlineElement)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
const configName = OutlineFilter.kindToConfigName[element.symbol.kind];
|
||||
const configKey = `${this._prefix}.${configName}`;
|
||||
return this._textResourceConfigService.getValue(uri, configKey);
|
||||
}
|
||||
}
|
||||
|
||||
export class OutlineItemComparator implements ITreeSorter<OutlineItem> {
|
||||
|
||||
private readonly _collator = new IdleValue<Intl.Collator>(() => new Intl.Collator(undefined, { numeric: true }));
|
||||
|
||||
constructor(
|
||||
public type: OutlineSortOrder = OutlineSortOrder.ByPosition
|
||||
) { }
|
||||
|
||||
compare(a: OutlineItem, b: OutlineItem): number {
|
||||
if (a instanceof OutlineGroup && b instanceof OutlineGroup) {
|
||||
return a.order - b.order;
|
||||
|
||||
} else if (a instanceof OutlineElement && b instanceof OutlineElement) {
|
||||
if (this.type === OutlineSortOrder.ByKind) {
|
||||
return a.symbol.kind - b.symbol.kind || this._collator.value.compare(a.symbol.name, b.symbol.name);
|
||||
} else if (this.type === OutlineSortOrder.ByName) {
|
||||
return this._collator.value.compare(a.symbol.name, b.symbol.name) || Range.compareRangesUsingStarts(a.symbol.range, b.symbol.range);
|
||||
} else if (this.type === OutlineSortOrder.ByPosition) {
|
||||
return Range.compareRangesUsingStarts(a.symbol.range, b.symbol.range) || this._collator.value.compare(a.symbol.name, b.symbol.name);
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
export class OutlineDataSource implements IDataSource<OutlineModel, OutlineItem> {
|
||||
|
||||
getChildren(element: undefined | OutlineModel | OutlineGroup | OutlineElement) {
|
||||
if (!element) {
|
||||
return Iterable.empty();
|
||||
}
|
||||
return element.children.values();
|
||||
}
|
||||
}
|
||||
|
||||
export const SYMBOL_ICON_ARRAY_FOREGROUND = registerColor('symbolIcon.arrayForeground', {
|
||||
dark: foreground,
|
||||
light: foreground,
|
||||
hc: foreground
|
||||
}, localize('symbolIcon.arrayForeground', 'The foreground color for array symbols. These symbols appear in the outline, breadcrumb, and suggest widget.'));
|
||||
|
||||
export const SYMBOL_ICON_BOOLEAN_FOREGROUND = registerColor('symbolIcon.booleanForeground', {
|
||||
dark: foreground,
|
||||
light: foreground,
|
||||
hc: foreground
|
||||
}, localize('symbolIcon.booleanForeground', 'The foreground color for boolean symbols. These symbols appear in the outline, breadcrumb, and suggest widget.'));
|
||||
|
||||
export const SYMBOL_ICON_CLASS_FOREGROUND = registerColor('symbolIcon.classForeground', {
|
||||
dark: '#EE9D28',
|
||||
light: '#D67E00',
|
||||
hc: '#EE9D28'
|
||||
}, localize('symbolIcon.classForeground', 'The foreground color for class symbols. These symbols appear in the outline, breadcrumb, and suggest widget.'));
|
||||
|
||||
export const SYMBOL_ICON_COLOR_FOREGROUND = registerColor('symbolIcon.colorForeground', {
|
||||
dark: foreground,
|
||||
light: foreground,
|
||||
hc: foreground
|
||||
}, localize('symbolIcon.colorForeground', 'The foreground color for color symbols. These symbols appear in the outline, breadcrumb, and suggest widget.'));
|
||||
|
||||
export const SYMBOL_ICON_CONSTANT_FOREGROUND = registerColor('symbolIcon.constantForeground', {
|
||||
dark: foreground,
|
||||
light: foreground,
|
||||
hc: foreground
|
||||
}, localize('symbolIcon.constantForeground', 'The foreground color for constant symbols. These symbols appear in the outline, breadcrumb, and suggest widget.'));
|
||||
|
||||
export const SYMBOL_ICON_CONSTRUCTOR_FOREGROUND = registerColor('symbolIcon.constructorForeground', {
|
||||
dark: '#B180D7',
|
||||
light: '#652D90',
|
||||
hc: '#B180D7'
|
||||
}, localize('symbolIcon.constructorForeground', 'The foreground color for constructor symbols. These symbols appear in the outline, breadcrumb, and suggest widget.'));
|
||||
|
||||
export const SYMBOL_ICON_ENUMERATOR_FOREGROUND = registerColor('symbolIcon.enumeratorForeground', {
|
||||
dark: '#EE9D28',
|
||||
light: '#D67E00',
|
||||
hc: '#EE9D28'
|
||||
}, localize('symbolIcon.enumeratorForeground', 'The foreground color for enumerator symbols. These symbols appear in the outline, breadcrumb, and suggest widget.'));
|
||||
|
||||
export const SYMBOL_ICON_ENUMERATOR_MEMBER_FOREGROUND = registerColor('symbolIcon.enumeratorMemberForeground', {
|
||||
dark: '#75BEFF',
|
||||
light: '#007ACC',
|
||||
hc: '#75BEFF'
|
||||
}, localize('symbolIcon.enumeratorMemberForeground', 'The foreground color for enumerator member symbols. These symbols appear in the outline, breadcrumb, and suggest widget.'));
|
||||
|
||||
export const SYMBOL_ICON_EVENT_FOREGROUND = registerColor('symbolIcon.eventForeground', {
|
||||
dark: '#EE9D28',
|
||||
light: '#D67E00',
|
||||
hc: '#EE9D28'
|
||||
}, localize('symbolIcon.eventForeground', 'The foreground color for event symbols. These symbols appear in the outline, breadcrumb, and suggest widget.'));
|
||||
|
||||
export const SYMBOL_ICON_FIELD_FOREGROUND = registerColor('symbolIcon.fieldForeground', {
|
||||
dark: '#75BEFF',
|
||||
light: '#007ACC',
|
||||
hc: '#75BEFF'
|
||||
}, localize('symbolIcon.fieldForeground', 'The foreground color for field symbols. These symbols appear in the outline, breadcrumb, and suggest widget.'));
|
||||
|
||||
export const SYMBOL_ICON_FILE_FOREGROUND = registerColor('symbolIcon.fileForeground', {
|
||||
dark: foreground,
|
||||
light: foreground,
|
||||
hc: foreground
|
||||
}, localize('symbolIcon.fileForeground', 'The foreground color for file symbols. These symbols appear in the outline, breadcrumb, and suggest widget.'));
|
||||
|
||||
export const SYMBOL_ICON_FOLDER_FOREGROUND = registerColor('symbolIcon.folderForeground', {
|
||||
dark: foreground,
|
||||
light: foreground,
|
||||
hc: foreground
|
||||
}, localize('symbolIcon.folderForeground', 'The foreground color for folder symbols. These symbols appear in the outline, breadcrumb, and suggest widget.'));
|
||||
|
||||
export const SYMBOL_ICON_FUNCTION_FOREGROUND = registerColor('symbolIcon.functionForeground', {
|
||||
dark: '#B180D7',
|
||||
light: '#652D90',
|
||||
hc: '#B180D7'
|
||||
}, localize('symbolIcon.functionForeground', 'The foreground color for function symbols. These symbols appear in the outline, breadcrumb, and suggest widget.'));
|
||||
|
||||
export const SYMBOL_ICON_INTERFACE_FOREGROUND = registerColor('symbolIcon.interfaceForeground', {
|
||||
dark: '#75BEFF',
|
||||
light: '#007ACC',
|
||||
hc: '#75BEFF'
|
||||
}, localize('symbolIcon.interfaceForeground', 'The foreground color for interface symbols. These symbols appear in the outline, breadcrumb, and suggest widget.'));
|
||||
|
||||
export const SYMBOL_ICON_KEY_FOREGROUND = registerColor('symbolIcon.keyForeground', {
|
||||
dark: foreground,
|
||||
light: foreground,
|
||||
hc: foreground
|
||||
}, localize('symbolIcon.keyForeground', 'The foreground color for key symbols. These symbols appear in the outline, breadcrumb, and suggest widget.'));
|
||||
|
||||
export const SYMBOL_ICON_KEYWORD_FOREGROUND = registerColor('symbolIcon.keywordForeground', {
|
||||
dark: foreground,
|
||||
light: foreground,
|
||||
hc: foreground
|
||||
}, localize('symbolIcon.keywordForeground', 'The foreground color for keyword symbols. These symbols appear in the outline, breadcrumb, and suggest widget.'));
|
||||
|
||||
export const SYMBOL_ICON_METHOD_FOREGROUND = registerColor('symbolIcon.methodForeground', {
|
||||
dark: '#B180D7',
|
||||
light: '#652D90',
|
||||
hc: '#B180D7'
|
||||
}, localize('symbolIcon.methodForeground', 'The foreground color for method symbols. These symbols appear in the outline, breadcrumb, and suggest widget.'));
|
||||
|
||||
export const SYMBOL_ICON_MODULE_FOREGROUND = registerColor('symbolIcon.moduleForeground', {
|
||||
dark: foreground,
|
||||
light: foreground,
|
||||
hc: foreground
|
||||
}, localize('symbolIcon.moduleForeground', 'The foreground color for module symbols. These symbols appear in the outline, breadcrumb, and suggest widget.'));
|
||||
|
||||
export const SYMBOL_ICON_NAMESPACE_FOREGROUND = registerColor('symbolIcon.namespaceForeground', {
|
||||
dark: foreground,
|
||||
light: foreground,
|
||||
hc: foreground
|
||||
}, localize('symbolIcon.namespaceForeground', 'The foreground color for namespace symbols. These symbols appear in the outline, breadcrumb, and suggest widget.'));
|
||||
|
||||
export const SYMBOL_ICON_NULL_FOREGROUND = registerColor('symbolIcon.nullForeground', {
|
||||
dark: foreground,
|
||||
light: foreground,
|
||||
hc: foreground
|
||||
}, localize('symbolIcon.nullForeground', 'The foreground color for null symbols. These symbols appear in the outline, breadcrumb, and suggest widget.'));
|
||||
|
||||
export const SYMBOL_ICON_NUMBER_FOREGROUND = registerColor('symbolIcon.numberForeground', {
|
||||
dark: foreground,
|
||||
light: foreground,
|
||||
hc: foreground
|
||||
}, localize('symbolIcon.numberForeground', 'The foreground color for number symbols. These symbols appear in the outline, breadcrumb, and suggest widget.'));
|
||||
|
||||
export const SYMBOL_ICON_OBJECT_FOREGROUND = registerColor('symbolIcon.objectForeground', {
|
||||
dark: foreground,
|
||||
light: foreground,
|
||||
hc: foreground
|
||||
}, localize('symbolIcon.objectForeground', 'The foreground color for object symbols. These symbols appear in the outline, breadcrumb, and suggest widget.'));
|
||||
|
||||
export const SYMBOL_ICON_OPERATOR_FOREGROUND = registerColor('symbolIcon.operatorForeground', {
|
||||
dark: foreground,
|
||||
light: foreground,
|
||||
hc: foreground
|
||||
}, localize('symbolIcon.operatorForeground', 'The foreground color for operator symbols. These symbols appear in the outline, breadcrumb, and suggest widget.'));
|
||||
|
||||
export const SYMBOL_ICON_PACKAGE_FOREGROUND = registerColor('symbolIcon.packageForeground', {
|
||||
dark: foreground,
|
||||
light: foreground,
|
||||
hc: foreground
|
||||
}, localize('symbolIcon.packageForeground', 'The foreground color for package symbols. These symbols appear in the outline, breadcrumb, and suggest widget.'));
|
||||
|
||||
export const SYMBOL_ICON_PROPERTY_FOREGROUND = registerColor('symbolIcon.propertyForeground', {
|
||||
dark: foreground,
|
||||
light: foreground,
|
||||
hc: foreground
|
||||
}, localize('symbolIcon.propertyForeground', 'The foreground color for property symbols. These symbols appear in the outline, breadcrumb, and suggest widget.'));
|
||||
|
||||
export const SYMBOL_ICON_REFERENCE_FOREGROUND = registerColor('symbolIcon.referenceForeground', {
|
||||
dark: foreground,
|
||||
light: foreground,
|
||||
hc: foreground
|
||||
}, localize('symbolIcon.referenceForeground', 'The foreground color for reference symbols. These symbols appear in the outline, breadcrumb, and suggest widget.'));
|
||||
|
||||
export const SYMBOL_ICON_SNIPPET_FOREGROUND = registerColor('symbolIcon.snippetForeground', {
|
||||
dark: foreground,
|
||||
light: foreground,
|
||||
hc: foreground
|
||||
}, localize('symbolIcon.snippetForeground', 'The foreground color for snippet symbols. These symbols appear in the outline, breadcrumb, and suggest widget.'));
|
||||
|
||||
export const SYMBOL_ICON_STRING_FOREGROUND = registerColor('symbolIcon.stringForeground', {
|
||||
dark: foreground,
|
||||
light: foreground,
|
||||
hc: foreground
|
||||
}, localize('symbolIcon.stringForeground', 'The foreground color for string symbols. These symbols appear in the outline, breadcrumb, and suggest widget.'));
|
||||
|
||||
export const SYMBOL_ICON_STRUCT_FOREGROUND = registerColor('symbolIcon.structForeground', {
|
||||
dark: foreground,
|
||||
light: foreground,
|
||||
hc: foreground
|
||||
}, localize('symbolIcon.structForeground', 'The foreground color for struct symbols. These symbols appear in the outline, breadcrumb, and suggest widget.'));
|
||||
|
||||
export const SYMBOL_ICON_TEXT_FOREGROUND = registerColor('symbolIcon.textForeground', {
|
||||
dark: foreground,
|
||||
light: foreground,
|
||||
hc: foreground
|
||||
}, localize('symbolIcon.textForeground', 'The foreground color for text symbols. These symbols appear in the outline, breadcrumb, and suggest widget.'));
|
||||
|
||||
export const SYMBOL_ICON_TYPEPARAMETER_FOREGROUND = registerColor('symbolIcon.typeParameterForeground', {
|
||||
dark: foreground,
|
||||
light: foreground,
|
||||
hc: foreground
|
||||
}, localize('symbolIcon.typeParameterForeground', 'The foreground color for type parameter symbols. These symbols appear in the outline, breadcrumb, and suggest widget.'));
|
||||
|
||||
export const SYMBOL_ICON_UNIT_FOREGROUND = registerColor('symbolIcon.unitForeground', {
|
||||
dark: foreground,
|
||||
light: foreground,
|
||||
hc: foreground
|
||||
}, localize('symbolIcon.unitForeground', 'The foreground color for unit symbols. These symbols appear in the outline, breadcrumb, and suggest widget.'));
|
||||
|
||||
export const SYMBOL_ICON_VARIABLE_FOREGROUND = registerColor('symbolIcon.variableForeground', {
|
||||
dark: '#75BEFF',
|
||||
light: '#007ACC',
|
||||
hc: '#75BEFF'
|
||||
}, localize('symbolIcon.variableForeground', 'The foreground color for variable symbols. These symbols appear in the outline, breadcrumb, and suggest widget.'));
|
||||
|
||||
registerThemingParticipant((theme: IColorTheme, collector: ICssStyleCollector) => {
|
||||
|
||||
const symbolIconArrayColor = theme.getColor(SYMBOL_ICON_ARRAY_FOREGROUND);
|
||||
if (symbolIconArrayColor) {
|
||||
collector.addRule(`${Codicon.symbolArray.cssSelector} { color: ${symbolIconArrayColor}; }`);
|
||||
}
|
||||
|
||||
const symbolIconBooleanColor = theme.getColor(SYMBOL_ICON_BOOLEAN_FOREGROUND);
|
||||
if (symbolIconBooleanColor) {
|
||||
collector.addRule(`${Codicon.symbolBoolean.cssSelector} { color: ${symbolIconBooleanColor}; }`);
|
||||
}
|
||||
|
||||
const symbolIconClassColor = theme.getColor(SYMBOL_ICON_CLASS_FOREGROUND);
|
||||
if (symbolIconClassColor) {
|
||||
collector.addRule(`${Codicon.symbolClass.cssSelector} { color: ${symbolIconClassColor}; }`);
|
||||
}
|
||||
|
||||
const symbolIconMethodColor = theme.getColor(SYMBOL_ICON_METHOD_FOREGROUND);
|
||||
if (symbolIconMethodColor) {
|
||||
collector.addRule(`${Codicon.symbolMethod.cssSelector} { color: ${symbolIconMethodColor}; }`);
|
||||
}
|
||||
|
||||
const symbolIconColorColor = theme.getColor(SYMBOL_ICON_COLOR_FOREGROUND);
|
||||
if (symbolIconColorColor) {
|
||||
collector.addRule(`${Codicon.symbolColor.cssSelector} { color: ${symbolIconColorColor}; }`);
|
||||
}
|
||||
|
||||
const symbolIconConstantColor = theme.getColor(SYMBOL_ICON_CONSTANT_FOREGROUND);
|
||||
if (symbolIconConstantColor) {
|
||||
collector.addRule(`${Codicon.symbolConstant.cssSelector} { color: ${symbolIconConstantColor}; }`);
|
||||
}
|
||||
|
||||
const symbolIconConstructorColor = theme.getColor(SYMBOL_ICON_CONSTRUCTOR_FOREGROUND);
|
||||
if (symbolIconConstructorColor) {
|
||||
collector.addRule(`${Codicon.symbolConstructor.cssSelector} { color: ${symbolIconConstructorColor}; }`);
|
||||
}
|
||||
|
||||
const symbolIconEnumeratorColor = theme.getColor(SYMBOL_ICON_ENUMERATOR_FOREGROUND);
|
||||
if (symbolIconEnumeratorColor) {
|
||||
collector.addRule(`
|
||||
${Codicon.symbolValue.cssSelector},${Codicon.symbolEnum.cssSelector} { color: ${symbolIconEnumeratorColor}; }`);
|
||||
}
|
||||
|
||||
const symbolIconEnumeratorMemberColor = theme.getColor(SYMBOL_ICON_ENUMERATOR_MEMBER_FOREGROUND);
|
||||
if (symbolIconEnumeratorMemberColor) {
|
||||
collector.addRule(`${Codicon.symbolEnumMember.cssSelector} { color: ${symbolIconEnumeratorMemberColor}; }`);
|
||||
}
|
||||
|
||||
const symbolIconEventColor = theme.getColor(SYMBOL_ICON_EVENT_FOREGROUND);
|
||||
if (symbolIconEventColor) {
|
||||
collector.addRule(`${Codicon.symbolEvent.cssSelector} { color: ${symbolIconEventColor}; }`);
|
||||
}
|
||||
|
||||
const symbolIconFieldColor = theme.getColor(SYMBOL_ICON_FIELD_FOREGROUND);
|
||||
if (symbolIconFieldColor) {
|
||||
collector.addRule(`${Codicon.symbolField.cssSelector} { color: ${symbolIconFieldColor}; }`);
|
||||
}
|
||||
|
||||
const symbolIconFileColor = theme.getColor(SYMBOL_ICON_FILE_FOREGROUND);
|
||||
if (symbolIconFileColor) {
|
||||
collector.addRule(`${Codicon.symbolFile.cssSelector} { color: ${symbolIconFileColor}; }`);
|
||||
}
|
||||
|
||||
const symbolIconFolderColor = theme.getColor(SYMBOL_ICON_FOLDER_FOREGROUND);
|
||||
if (symbolIconFolderColor) {
|
||||
collector.addRule(`${Codicon.symbolFolder.cssSelector} { color: ${symbolIconFolderColor}; }`);
|
||||
}
|
||||
|
||||
const symbolIconFunctionColor = theme.getColor(SYMBOL_ICON_FUNCTION_FOREGROUND);
|
||||
if (symbolIconFunctionColor) {
|
||||
collector.addRule(`${Codicon.symbolFunction.cssSelector} { color: ${symbolIconFunctionColor}; }`);
|
||||
}
|
||||
|
||||
const symbolIconInterfaceColor = theme.getColor(SYMBOL_ICON_INTERFACE_FOREGROUND);
|
||||
if (symbolIconInterfaceColor) {
|
||||
collector.addRule(`${Codicon.symbolInterface.cssSelector} { color: ${symbolIconInterfaceColor}; }`);
|
||||
}
|
||||
|
||||
const symbolIconKeyColor = theme.getColor(SYMBOL_ICON_KEY_FOREGROUND);
|
||||
if (symbolIconKeyColor) {
|
||||
collector.addRule(`${Codicon.symbolKey.cssSelector} { color: ${symbolIconKeyColor}; }`);
|
||||
}
|
||||
|
||||
const symbolIconKeywordColor = theme.getColor(SYMBOL_ICON_KEYWORD_FOREGROUND);
|
||||
if (symbolIconKeywordColor) {
|
||||
collector.addRule(`${Codicon.symbolKeyword.cssSelector} { color: ${symbolIconKeywordColor}; }`);
|
||||
}
|
||||
|
||||
const symbolIconModuleColor = theme.getColor(SYMBOL_ICON_MODULE_FOREGROUND);
|
||||
if (symbolIconModuleColor) {
|
||||
collector.addRule(`${Codicon.symbolModule.cssSelector} { color: ${symbolIconModuleColor}; }`);
|
||||
}
|
||||
|
||||
const outlineNamespaceColor = theme.getColor(SYMBOL_ICON_NAMESPACE_FOREGROUND);
|
||||
if (outlineNamespaceColor) {
|
||||
collector.addRule(`${Codicon.symbolNamespace.cssSelector} { color: ${outlineNamespaceColor}; }`);
|
||||
}
|
||||
|
||||
const symbolIconNullColor = theme.getColor(SYMBOL_ICON_NULL_FOREGROUND);
|
||||
if (symbolIconNullColor) {
|
||||
collector.addRule(`${Codicon.symbolNull.cssSelector} { color: ${symbolIconNullColor}; }`);
|
||||
}
|
||||
|
||||
const symbolIconNumberColor = theme.getColor(SYMBOL_ICON_NUMBER_FOREGROUND);
|
||||
if (symbolIconNumberColor) {
|
||||
collector.addRule(`${Codicon.symbolNumber.cssSelector} { color: ${symbolIconNumberColor}; }`);
|
||||
}
|
||||
|
||||
const symbolIconObjectColor = theme.getColor(SYMBOL_ICON_OBJECT_FOREGROUND);
|
||||
if (symbolIconObjectColor) {
|
||||
collector.addRule(`${Codicon.symbolObject.cssSelector} { color: ${symbolIconObjectColor}; }`);
|
||||
}
|
||||
|
||||
const symbolIconOperatorColor = theme.getColor(SYMBOL_ICON_OPERATOR_FOREGROUND);
|
||||
if (symbolIconOperatorColor) {
|
||||
collector.addRule(`${Codicon.symbolOperator.cssSelector} { color: ${symbolIconOperatorColor}; }`);
|
||||
}
|
||||
|
||||
const symbolIconPackageColor = theme.getColor(SYMBOL_ICON_PACKAGE_FOREGROUND);
|
||||
if (symbolIconPackageColor) {
|
||||
collector.addRule(`${Codicon.symbolPackage.cssSelector} { color: ${symbolIconPackageColor}; }`);
|
||||
}
|
||||
|
||||
const symbolIconPropertyColor = theme.getColor(SYMBOL_ICON_PROPERTY_FOREGROUND);
|
||||
if (symbolIconPropertyColor) {
|
||||
collector.addRule(`${Codicon.symbolProperty.cssSelector} { color: ${symbolIconPropertyColor}; }`);
|
||||
}
|
||||
|
||||
const symbolIconReferenceColor = theme.getColor(SYMBOL_ICON_REFERENCE_FOREGROUND);
|
||||
if (symbolIconReferenceColor) {
|
||||
collector.addRule(`${Codicon.symbolReference.cssSelector} { color: ${symbolIconReferenceColor}; }`);
|
||||
}
|
||||
|
||||
const symbolIconSnippetColor = theme.getColor(SYMBOL_ICON_SNIPPET_FOREGROUND);
|
||||
if (symbolIconSnippetColor) {
|
||||
collector.addRule(`${Codicon.symbolSnippet.cssSelector} { color: ${symbolIconSnippetColor}; }`);
|
||||
}
|
||||
|
||||
const symbolIconStringColor = theme.getColor(SYMBOL_ICON_STRING_FOREGROUND);
|
||||
if (symbolIconStringColor) {
|
||||
collector.addRule(`${Codicon.symbolString.cssSelector} { color: ${symbolIconStringColor}; }`);
|
||||
}
|
||||
|
||||
const symbolIconStructColor = theme.getColor(SYMBOL_ICON_STRUCT_FOREGROUND);
|
||||
if (symbolIconStructColor) {
|
||||
collector.addRule(`${Codicon.symbolStruct.cssSelector} { color: ${symbolIconStructColor}; }`);
|
||||
}
|
||||
|
||||
const symbolIconTextColor = theme.getColor(SYMBOL_ICON_TEXT_FOREGROUND);
|
||||
if (symbolIconTextColor) {
|
||||
collector.addRule(`${Codicon.symbolText.cssSelector} { color: ${symbolIconTextColor}; }`);
|
||||
}
|
||||
|
||||
const symbolIconTypeParameterColor = theme.getColor(SYMBOL_ICON_TYPEPARAMETER_FOREGROUND);
|
||||
if (symbolIconTypeParameterColor) {
|
||||
collector.addRule(`${Codicon.symbolTypeParameter.cssSelector} { color: ${symbolIconTypeParameterColor}; }`);
|
||||
}
|
||||
|
||||
const symbolIconUnitColor = theme.getColor(SYMBOL_ICON_UNIT_FOREGROUND);
|
||||
if (symbolIconUnitColor) {
|
||||
collector.addRule(`${Codicon.symbolUnit.cssSelector} { color: ${symbolIconUnitColor}; }`);
|
||||
}
|
||||
|
||||
const symbolIconVariableColor = theme.getColor(SYMBOL_ICON_VARIABLE_FOREGROUND);
|
||||
if (symbolIconVariableColor) {
|
||||
collector.addRule(`${Codicon.symbolVariable.cssSelector} { color: ${symbolIconVariableColor}; }`);
|
||||
}
|
||||
|
||||
});
|
||||
@@ -60,14 +60,14 @@
|
||||
}
|
||||
|
||||
|
||||
.monaco-editor .find-widget > .replace-part .monaco-inputbox > .wrapper > .mirror {
|
||||
.monaco-editor .find-widget > .replace-part .monaco-inputbox > .ibwrapper > .mirror {
|
||||
padding-right: 22px;
|
||||
}
|
||||
|
||||
.monaco-editor .find-widget > .find-part .monaco-inputbox > .wrapper > .input,
|
||||
.monaco-editor .find-widget > .find-part .monaco-inputbox > .wrapper > .mirror,
|
||||
.monaco-editor .find-widget > .replace-part .monaco-inputbox > .wrapper > .input,
|
||||
.monaco-editor .find-widget > .replace-part .monaco-inputbox > .wrapper > .mirror {
|
||||
.monaco-editor .find-widget > .find-part .monaco-inputbox > .ibwrapper > .input,
|
||||
.monaco-editor .find-widget > .find-part .monaco-inputbox > .ibwrapper > .mirror,
|
||||
.monaco-editor .find-widget > .replace-part .monaco-inputbox > .ibwrapper > .input,
|
||||
.monaco-editor .find-widget > .replace-part .monaco-inputbox > .ibwrapper > .mirror {
|
||||
padding-top: 2px;
|
||||
padding-bottom: 2px;
|
||||
}
|
||||
|
||||
@@ -1044,7 +1044,7 @@ export class FindWidget extends Widget implements IOverlayWidget, IVerticalSashL
|
||||
|
||||
// Toggle selection button
|
||||
this._toggleSelectionFind = this._register(new Checkbox({
|
||||
icon: ThemeIcon.asCSSIcon(findSelectionIcon),
|
||||
icon: findSelectionIcon,
|
||||
title: NLS_TOGGLE_SELECTION_FIND_TITLE + this._keybindingLabelFor(FIND_IDS.ToggleSearchScopeCommand),
|
||||
isChecked: false
|
||||
}));
|
||||
|
||||
@@ -20,17 +20,17 @@ suite('Find', () => {
|
||||
|
||||
// The cursor is at the very top, of the file, at the first ABC
|
||||
let searchStringAtTop = getSelectionSearchString(editor);
|
||||
assert.equal(searchStringAtTop, 'ABC');
|
||||
assert.strictEqual(searchStringAtTop, 'ABC');
|
||||
|
||||
// Move cursor to the end of ABC
|
||||
editor.setPosition(new Position(1, 3));
|
||||
let searchStringAfterABC = getSelectionSearchString(editor);
|
||||
assert.equal(searchStringAfterABC, 'ABC');
|
||||
assert.strictEqual(searchStringAfterABC, 'ABC');
|
||||
|
||||
// Move cursor to DEF
|
||||
editor.setPosition(new Position(1, 5));
|
||||
let searchStringInsideDEF = getSelectionSearchString(editor);
|
||||
assert.equal(searchStringInsideDEF, 'DEF');
|
||||
assert.strictEqual(searchStringInsideDEF, 'DEF');
|
||||
|
||||
});
|
||||
});
|
||||
@@ -44,17 +44,17 @@ suite('Find', () => {
|
||||
// Select A of ABC
|
||||
editor.setSelection(new Range(1, 1, 1, 2));
|
||||
let searchStringSelectionA = getSelectionSearchString(editor);
|
||||
assert.equal(searchStringSelectionA, 'A');
|
||||
assert.strictEqual(searchStringSelectionA, 'A');
|
||||
|
||||
// Select BC of ABC
|
||||
editor.setSelection(new Range(1, 2, 1, 4));
|
||||
let searchStringSelectionBC = getSelectionSearchString(editor);
|
||||
assert.equal(searchStringSelectionBC, 'BC');
|
||||
assert.strictEqual(searchStringSelectionBC, 'BC');
|
||||
|
||||
// Select BC DE
|
||||
editor.setSelection(new Range(1, 2, 1, 7));
|
||||
let searchStringSelectionBCDE = getSelectionSearchString(editor);
|
||||
assert.equal(searchStringSelectionBCDE, 'BC DE');
|
||||
assert.strictEqual(searchStringSelectionBCDE, 'BC DE');
|
||||
|
||||
});
|
||||
});
|
||||
@@ -68,17 +68,17 @@ suite('Find', () => {
|
||||
// Select first line and newline
|
||||
editor.setSelection(new Range(1, 1, 2, 1));
|
||||
let searchStringSelectionWholeLine = getSelectionSearchString(editor);
|
||||
assert.equal(searchStringSelectionWholeLine, null);
|
||||
assert.strictEqual(searchStringSelectionWholeLine, null);
|
||||
|
||||
// Select first line and chunk of second
|
||||
editor.setSelection(new Range(1, 1, 2, 4));
|
||||
let searchStringSelectionTwoLines = getSelectionSearchString(editor);
|
||||
assert.equal(searchStringSelectionTwoLines, null);
|
||||
assert.strictEqual(searchStringSelectionTwoLines, null);
|
||||
|
||||
// Select end of first line newline and chunk of second
|
||||
editor.setSelection(new Range(1, 7, 2, 4));
|
||||
let searchStringSelectionSpanLines = getSelectionSearchString(editor);
|
||||
assert.equal(searchStringSelectionSpanLines, null);
|
||||
assert.strictEqual(searchStringSelectionSpanLines, null);
|
||||
|
||||
});
|
||||
});
|
||||
|
||||
@@ -102,7 +102,7 @@ suite('FindController', async () => {
|
||||
// I hit Ctrl+F to show the Find dialog
|
||||
startFindAction.run(null, editor);
|
||||
|
||||
assert.deepEqual(findController.getGlobalBufferTerm(), findController.getState().searchString);
|
||||
assert.deepStrictEqual(findController.getGlobalBufferTerm(), findController.getState().searchString);
|
||||
findController.dispose();
|
||||
});
|
||||
});
|
||||
@@ -126,9 +126,9 @@ suite('FindController', async () => {
|
||||
let nextMatchFindAction = new NextMatchFindAction();
|
||||
|
||||
nextMatchFindAction.run(null, editor);
|
||||
assert.equal(findState.searchString, 'ABC');
|
||||
assert.strictEqual(findState.searchString, 'ABC');
|
||||
|
||||
assert.deepEqual(fromSelection(editor.getSelection()!), [1, 1, 1, 4]);
|
||||
assert.deepStrictEqual(fromSelection(editor.getSelection()!), [1, 1, 1, 4]);
|
||||
|
||||
findController.dispose();
|
||||
});
|
||||
@@ -152,7 +152,7 @@ suite('FindController', async () => {
|
||||
|
||||
findState.change({ searchString: 'ABC' }, true);
|
||||
|
||||
assert.deepEqual(findController.getGlobalBufferTerm(), 'ABC');
|
||||
assert.deepStrictEqual(findController.getGlobalBufferTerm(), 'ABC');
|
||||
|
||||
findController.dispose();
|
||||
});
|
||||
@@ -181,14 +181,14 @@ suite('FindController', async () => {
|
||||
findState.change({ searchString: 'ABC' }, true);
|
||||
|
||||
// The first ABC is highlighted.
|
||||
assert.deepEqual(fromSelection(editor.getSelection()!), [1, 1, 1, 4]);
|
||||
assert.deepStrictEqual(fromSelection(editor.getSelection()!), [1, 1, 1, 4]);
|
||||
|
||||
// I hit Esc to exit the Find dialog.
|
||||
findController.closeFindWidget();
|
||||
findController.hasFocus = false;
|
||||
|
||||
// The cursor is now at end of the first line, with ABC on that line highlighted.
|
||||
assert.deepEqual(fromSelection(editor.getSelection()!), [1, 1, 1, 4]);
|
||||
assert.deepStrictEqual(fromSelection(editor.getSelection()!), [1, 1, 1, 4]);
|
||||
|
||||
// I hit delete to remove it and change the text to XYZ.
|
||||
editor.pushUndoStop();
|
||||
@@ -201,16 +201,16 @@ suite('FindController', async () => {
|
||||
// ABC
|
||||
// XYZ
|
||||
// ABC
|
||||
assert.equal(editor.getModel()!.getLineContent(1), 'XYZ');
|
||||
assert.strictEqual(editor.getModel()!.getLineContent(1), 'XYZ');
|
||||
|
||||
// The cursor is at end of the first line.
|
||||
assert.deepEqual(fromSelection(editor.getSelection()!), [1, 4, 1, 4]);
|
||||
assert.deepStrictEqual(fromSelection(editor.getSelection()!), [1, 4, 1, 4]);
|
||||
|
||||
// I hit F3 to "Find Next" to find the next occurrence of ABC, but instead it searches for XYZ.
|
||||
await nextMatchFindAction.run(null, editor);
|
||||
|
||||
assert.equal(findState.searchString, 'ABC');
|
||||
assert.equal(findController.hasFocus, false);
|
||||
assert.strictEqual(findState.searchString, 'ABC');
|
||||
assert.strictEqual(findController.hasFocus, false);
|
||||
|
||||
findController.dispose();
|
||||
});
|
||||
@@ -230,10 +230,10 @@ suite('FindController', async () => {
|
||||
});
|
||||
|
||||
await nextMatchFindAction.run(null, editor);
|
||||
assert.deepEqual(fromSelection(editor.getSelection()!), [1, 26, 1, 29]);
|
||||
assert.deepStrictEqual(fromSelection(editor.getSelection()!), [1, 26, 1, 29]);
|
||||
|
||||
await nextMatchFindAction.run(null, editor);
|
||||
assert.deepEqual(fromSelection(editor.getSelection()!), [1, 8, 1, 11]);
|
||||
assert.deepStrictEqual(fromSelection(editor.getSelection()!), [1, 8, 1, 11]);
|
||||
|
||||
findController.dispose();
|
||||
});
|
||||
@@ -256,10 +256,10 @@ suite('FindController', async () => {
|
||||
await startFindAction.run(null, editor);
|
||||
|
||||
await nextMatchFindAction.run(null, editor);
|
||||
assert.deepEqual(fromSelection(editor.getSelection()!), [2, 9, 2, 13]);
|
||||
assert.deepStrictEqual(fromSelection(editor.getSelection()!), [2, 9, 2, 13]);
|
||||
|
||||
await nextMatchFindAction.run(null, editor);
|
||||
assert.deepEqual(fromSelection(editor.getSelection()!), [1, 9, 1, 13]);
|
||||
assert.deepStrictEqual(fromSelection(editor.getSelection()!), [1, 9, 1, 13]);
|
||||
|
||||
findController.dispose();
|
||||
});
|
||||
@@ -288,7 +288,7 @@ suite('FindController', async () => {
|
||||
await nextMatchFindAction.run(null, editor);
|
||||
await startFindReplaceAction.run(null, editor);
|
||||
|
||||
assert.equal(findController.getState().searchString, testRegexString);
|
||||
assert.strictEqual(findController.getState().searchString, testRegexString);
|
||||
|
||||
findController.dispose();
|
||||
});
|
||||
@@ -312,16 +312,16 @@ suite('FindController', async () => {
|
||||
loop: true
|
||||
});
|
||||
|
||||
assert.equal(findController.getState().searchScope, null);
|
||||
assert.strictEqual(findController.getState().searchScope, null);
|
||||
|
||||
findController.getState().change({
|
||||
searchScope: [new Range(1, 1, 1, 5)]
|
||||
}, false);
|
||||
|
||||
assert.deepEqual(findController.getState().searchScope, [new Range(1, 1, 1, 5)]);
|
||||
assert.deepStrictEqual(findController.getState().searchScope, [new Range(1, 1, 1, 5)]);
|
||||
|
||||
findController.closeFindWidget();
|
||||
assert.equal(findController.getState().searchScope, null);
|
||||
assert.strictEqual(findController.getState().searchScope, null);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -338,13 +338,13 @@ suite('FindController', async () => {
|
||||
findController.getState().change({ searchString: '\\b\\s{3}\\b', replaceString: ' ', isRegex: true }, false);
|
||||
findController.moveToNextMatch();
|
||||
|
||||
assert.deepEqual(editor.getSelections()!.map(fromSelection), [
|
||||
assert.deepStrictEqual(editor.getSelections()!.map(fromSelection), [
|
||||
[1, 39, 1, 42]
|
||||
]);
|
||||
|
||||
findController.replace();
|
||||
|
||||
assert.deepEqual(editor.getValue(), 'HRESULT OnAmbientPropertyChange(DISPID dispid);');
|
||||
assert.deepStrictEqual(editor.getValue(), 'HRESULT OnAmbientPropertyChange(DISPID dispid);');
|
||||
|
||||
findController.dispose();
|
||||
});
|
||||
@@ -365,13 +365,13 @@ suite('FindController', async () => {
|
||||
findController.getState().change({ searchString: '^', replaceString: 'x', isRegex: true }, false);
|
||||
findController.moveToNextMatch();
|
||||
|
||||
assert.deepEqual(editor.getSelections()!.map(fromSelection), [
|
||||
assert.deepStrictEqual(editor.getSelections()!.map(fromSelection), [
|
||||
[2, 1, 2, 1]
|
||||
]);
|
||||
|
||||
findController.replace();
|
||||
|
||||
assert.deepEqual(editor.getValue(), '\nxline2\nline3');
|
||||
assert.deepStrictEqual(editor.getValue(), '\nxline2\nline3');
|
||||
|
||||
findController.dispose();
|
||||
});
|
||||
@@ -396,7 +396,7 @@ suite('FindController', async () => {
|
||||
// cmd+f3
|
||||
await nextSelectionMatchFindAction.run(null, editor);
|
||||
|
||||
assert.deepEqual(editor.getSelections()!.map(fromSelection), [
|
||||
assert.deepStrictEqual(editor.getSelections()!.map(fromSelection), [
|
||||
[3, 1, 3, 9]
|
||||
]);
|
||||
|
||||
@@ -427,7 +427,7 @@ suite('FindController', async () => {
|
||||
// cmd+f3
|
||||
await nextSelectionMatchFindAction.run(null, editor);
|
||||
|
||||
assert.deepEqual(editor.getSelections()!.map(fromSelection), [
|
||||
assert.deepStrictEqual(editor.getSelections()!.map(fromSelection), [
|
||||
[3, 1, 3, 9]
|
||||
]);
|
||||
|
||||
@@ -458,7 +458,7 @@ suite('FindController', async () => {
|
||||
await startFindWithSelectionAction.run(null, editor);
|
||||
let findState = findController.getState();
|
||||
|
||||
assert.deepEqual(findState.searchString.split(/\r\n|\r|\n/g), ['ABC', 'ABC']);
|
||||
assert.deepStrictEqual(findState.searchString.split(/\r\n|\r|\n/g), ['ABC', 'ABC']);
|
||||
|
||||
editor.setSelection(new Selection(3, 1, 3, 1));
|
||||
await startFindWithSelectionAction.run(null, editor);
|
||||
@@ -483,7 +483,7 @@ suite('FindController', async () => {
|
||||
startFindWithSelectionAction.run(null, editor);
|
||||
|
||||
let findState = findController.getState();
|
||||
assert.deepEqual(findState.searchString, 'ABC');
|
||||
assert.deepStrictEqual(findState.searchString, 'ABC');
|
||||
findController.dispose();
|
||||
});
|
||||
});
|
||||
@@ -531,7 +531,7 @@ suite('FindController query options persistence', async () => {
|
||||
// I type ABC.
|
||||
findState.change({ searchString: 'ABC' }, true);
|
||||
// The second ABC is highlighted as matchCase is true.
|
||||
assert.deepEqual(fromSelection(editor.getSelection()!), [2, 1, 2, 4]);
|
||||
assert.deepStrictEqual(fromSelection(editor.getSelection()!), [2, 1, 2, 4]);
|
||||
|
||||
findController.dispose();
|
||||
});
|
||||
@@ -558,7 +558,7 @@ suite('FindController query options persistence', async () => {
|
||||
// I type AB.
|
||||
findState.change({ searchString: 'AB' }, true);
|
||||
// The second AB is highlighted as wholeWord is true.
|
||||
assert.deepEqual(fromSelection(editor.getSelection()!), [2, 1, 2, 3]);
|
||||
assert.deepStrictEqual(fromSelection(editor.getSelection()!), [2, 1, 2, 3]);
|
||||
|
||||
findController.dispose();
|
||||
});
|
||||
@@ -575,7 +575,7 @@ suite('FindController query options persistence', async () => {
|
||||
// The cursor is at the very top, of the file, at the first ABC
|
||||
let findController = editor.registerAndInstantiateContribution(TestFindController.ID, TestFindController);
|
||||
findController.toggleRegex();
|
||||
assert.equal(queryState['editor.isRegex'], true);
|
||||
assert.strictEqual(queryState['editor.isRegex'], true);
|
||||
|
||||
findController.dispose();
|
||||
});
|
||||
@@ -601,13 +601,13 @@ suite('FindController query options persistence', async () => {
|
||||
|
||||
editor.setSelection(new Range(1, 1, 2, 1));
|
||||
findController.start(findConfig);
|
||||
assert.deepEqual(findController.getState().searchScope, [new Selection(1, 1, 2, 1)]);
|
||||
assert.deepStrictEqual(findController.getState().searchScope, [new Selection(1, 1, 2, 1)]);
|
||||
|
||||
findController.closeFindWidget();
|
||||
|
||||
editor.setSelections([new Selection(1, 1, 2, 1), new Selection(2, 1, 2, 5)]);
|
||||
findController.start(findConfig);
|
||||
assert.deepEqual(findController.getState().searchScope, [new Selection(1, 1, 2, 1), new Selection(2, 1, 2, 5)]);
|
||||
assert.deepStrictEqual(findController.getState().searchScope, [new Selection(1, 1, 2, 1), new Selection(2, 1, 2, 5)]);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -631,7 +631,7 @@ suite('FindController query options persistence', async () => {
|
||||
loop: true
|
||||
});
|
||||
|
||||
assert.deepEqual(findController.getState().searchScope, null);
|
||||
assert.deepStrictEqual(findController.getState().searchScope, null);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -655,7 +655,7 @@ suite('FindController query options persistence', async () => {
|
||||
loop: true
|
||||
});
|
||||
|
||||
assert.deepEqual(findController.getState().searchScope, [new Selection(1, 2, 1, 3)]);
|
||||
assert.deepStrictEqual(findController.getState().searchScope, [new Selection(1, 2, 1, 3)]);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -680,7 +680,7 @@ suite('FindController query options persistence', async () => {
|
||||
loop: true
|
||||
});
|
||||
|
||||
assert.deepEqual(findController.getState().searchScope, [new Selection(1, 6, 2, 1)]);
|
||||
assert.deepStrictEqual(findController.getState().searchScope, [new Selection(1, 6, 2, 1)]);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -81,13 +81,13 @@ suite('FindModel', () => {
|
||||
}
|
||||
|
||||
function assertFindState(editor: ICodeEditor, cursor: number[], highlighted: number[] | null, findDecorations: number[][]): void {
|
||||
assert.deepEqual(fromRange(editor.getSelection()!), cursor, 'cursor');
|
||||
assert.deepStrictEqual(fromRange(editor.getSelection()!), cursor, 'cursor');
|
||||
|
||||
let expectedState = {
|
||||
highlighted: highlighted ? [highlighted] : [],
|
||||
findDecorations: findDecorations
|
||||
};
|
||||
assert.deepEqual(_getFindState(editor), expectedState, 'state');
|
||||
assert.deepStrictEqual(_getFindState(editor), expectedState, 'state');
|
||||
}
|
||||
|
||||
findTest('incremental find from beginning of file', (editor) => {
|
||||
@@ -245,7 +245,7 @@ suite('FindModel', () => {
|
||||
findState.change({ searchString: 'hello' }, false);
|
||||
let findModel = new FindModelBoundToEditorModel(editor, findState);
|
||||
|
||||
assert.equal(findState.matchesCount, 5);
|
||||
assert.strictEqual(findState.matchesCount, 5);
|
||||
assertFindState(
|
||||
editor,
|
||||
[1, 1, 1, 1],
|
||||
@@ -275,7 +275,7 @@ suite('FindModel', () => {
|
||||
findState.change({ searchString: 'hello' }, false);
|
||||
let findModel = new FindModelBoundToEditorModel(editor, findState);
|
||||
|
||||
assert.equal(findState.matchesCount, 5);
|
||||
assert.strictEqual(findState.matchesCount, 5);
|
||||
assertFindState(
|
||||
editor,
|
||||
[1, 1, 1, 1],
|
||||
@@ -290,7 +290,7 @@ suite('FindModel', () => {
|
||||
);
|
||||
|
||||
findState.change({ searchString: 'helloo' }, false);
|
||||
assert.equal(findState.matchesCount, 0);
|
||||
assert.strictEqual(findState.matchesCount, 0);
|
||||
assertFindState(
|
||||
editor,
|
||||
[1, 1, 1, 1],
|
||||
@@ -1306,7 +1306,7 @@ suite('FindModel', () => {
|
||||
[8, 14, 8, 19]
|
||||
]
|
||||
);
|
||||
assert.equal(editor.getModel()!.getLineContent(6), ' cout << "hello world, Hello!" << endl;');
|
||||
assert.strictEqual(editor.getModel()!.getLineContent(6), ' cout << "hello world, Hello!" << endl;');
|
||||
|
||||
findModel.replace();
|
||||
assertFindState(
|
||||
@@ -1320,7 +1320,7 @@ suite('FindModel', () => {
|
||||
[8, 14, 8, 19]
|
||||
]
|
||||
);
|
||||
assert.equal(editor.getModel()!.getLineContent(6), ' cout << "hello world, Hello!" << endl;');
|
||||
assert.strictEqual(editor.getModel()!.getLineContent(6), ' cout << "hello world, Hello!" << endl;');
|
||||
|
||||
findModel.replace();
|
||||
assertFindState(
|
||||
@@ -1333,7 +1333,7 @@ suite('FindModel', () => {
|
||||
[8, 14, 8, 19]
|
||||
]
|
||||
);
|
||||
assert.equal(editor.getModel()!.getLineContent(6), ' cout << "hello world, hi!" << endl;');
|
||||
assert.strictEqual(editor.getModel()!.getLineContent(6), ' cout << "hello world, hi!" << endl;');
|
||||
|
||||
findModel.replace();
|
||||
assertFindState(
|
||||
@@ -1345,7 +1345,7 @@ suite('FindModel', () => {
|
||||
[8, 14, 8, 19]
|
||||
]
|
||||
);
|
||||
assert.equal(editor.getModel()!.getLineContent(7), ' cout << "hi world again" << endl;');
|
||||
assert.strictEqual(editor.getModel()!.getLineContent(7), ' cout << "hi world again" << endl;');
|
||||
|
||||
findModel.replace();
|
||||
assertFindState(
|
||||
@@ -1356,7 +1356,7 @@ suite('FindModel', () => {
|
||||
[6, 14, 6, 19]
|
||||
]
|
||||
);
|
||||
assert.equal(editor.getModel()!.getLineContent(8), ' cout << "hi world again" << endl;');
|
||||
assert.strictEqual(editor.getModel()!.getLineContent(8), ' cout << "hi world again" << endl;');
|
||||
|
||||
findModel.replace();
|
||||
assertFindState(
|
||||
@@ -1365,7 +1365,7 @@ suite('FindModel', () => {
|
||||
null,
|
||||
[]
|
||||
);
|
||||
assert.equal(editor.getModel()!.getLineContent(6), ' cout << "hi world, hi!" << endl;');
|
||||
assert.strictEqual(editor.getModel()!.getLineContent(6), ' cout << "hi world, hi!" << endl;');
|
||||
|
||||
findModel.dispose();
|
||||
findState.dispose();
|
||||
@@ -1398,7 +1398,7 @@ suite('FindModel', () => {
|
||||
[11, 10, 11, 13]
|
||||
]
|
||||
);
|
||||
assert.equal(editor.getModel()!.getLineContent(11), '// blablablaciao');
|
||||
assert.strictEqual(editor.getModel()!.getLineContent(11), '// blablablaciao');
|
||||
|
||||
findModel.replace();
|
||||
assertFindState(
|
||||
@@ -1410,7 +1410,7 @@ suite('FindModel', () => {
|
||||
[11, 11, 11, 14]
|
||||
]
|
||||
);
|
||||
assert.equal(editor.getModel()!.getLineContent(11), '// ciaoblablaciao');
|
||||
assert.strictEqual(editor.getModel()!.getLineContent(11), '// ciaoblablaciao');
|
||||
|
||||
findModel.replace();
|
||||
assertFindState(
|
||||
@@ -1421,7 +1421,7 @@ suite('FindModel', () => {
|
||||
[11, 12, 11, 15]
|
||||
]
|
||||
);
|
||||
assert.equal(editor.getModel()!.getLineContent(11), '// ciaociaoblaciao');
|
||||
assert.strictEqual(editor.getModel()!.getLineContent(11), '// ciaociaoblaciao');
|
||||
|
||||
findModel.replace();
|
||||
assertFindState(
|
||||
@@ -1430,7 +1430,7 @@ suite('FindModel', () => {
|
||||
null,
|
||||
[]
|
||||
);
|
||||
assert.equal(editor.getModel()!.getLineContent(11), '// ciaociaociaociao');
|
||||
assert.strictEqual(editor.getModel()!.getLineContent(11), '// ciaociaociaociao');
|
||||
|
||||
findModel.dispose();
|
||||
findState.dispose();
|
||||
@@ -1467,7 +1467,7 @@ suite('FindModel', () => {
|
||||
[8, 14, 8, 19]
|
||||
]
|
||||
);
|
||||
assert.equal(editor.getModel()!.getLineContent(6), ' cout << "hello world, Hello!" << endl;');
|
||||
assert.strictEqual(editor.getModel()!.getLineContent(6), ' cout << "hello world, Hello!" << endl;');
|
||||
|
||||
findModel.replaceAll();
|
||||
assertFindState(
|
||||
@@ -1476,9 +1476,9 @@ suite('FindModel', () => {
|
||||
null,
|
||||
[]
|
||||
);
|
||||
assert.equal(editor.getModel()!.getLineContent(6), ' cout << "hi world, hi!" << endl;');
|
||||
assert.equal(editor.getModel()!.getLineContent(7), ' cout << "hi world again" << endl;');
|
||||
assert.equal(editor.getModel()!.getLineContent(8), ' cout << "hi world again" << endl;');
|
||||
assert.strictEqual(editor.getModel()!.getLineContent(6), ' cout << "hi world, hi!" << endl;');
|
||||
assert.strictEqual(editor.getModel()!.getLineContent(7), ' cout << "hi world again" << endl;');
|
||||
assert.strictEqual(editor.getModel()!.getLineContent(8), ' cout << "hi world again" << endl;');
|
||||
|
||||
findModel.dispose();
|
||||
findState.dispose();
|
||||
@@ -1517,10 +1517,10 @@ suite('FindModel', () => {
|
||||
[9, 1, 9, 3]
|
||||
]
|
||||
);
|
||||
assert.equal(editor.getModel()!.getLineContent(6), ' cout << "hello world, Hello!" << endl;');
|
||||
assert.equal(editor.getModel()!.getLineContent(7), ' cout << "hello world again" << endl;');
|
||||
assert.equal(editor.getModel()!.getLineContent(8), ' cout << "Hello world again" << endl;');
|
||||
assert.equal(editor.getModel()!.getLineContent(9), ' cout << "helloworld again" << endl;');
|
||||
assert.strictEqual(editor.getModel()!.getLineContent(6), ' cout << "hello world, Hello!" << endl;');
|
||||
assert.strictEqual(editor.getModel()!.getLineContent(7), ' cout << "hello world again" << endl;');
|
||||
assert.strictEqual(editor.getModel()!.getLineContent(8), ' cout << "Hello world again" << endl;');
|
||||
assert.strictEqual(editor.getModel()!.getLineContent(9), ' cout << "helloworld again" << endl;');
|
||||
|
||||
findModel.dispose();
|
||||
findState.dispose();
|
||||
@@ -1549,7 +1549,7 @@ suite('FindModel', () => {
|
||||
null,
|
||||
[]
|
||||
);
|
||||
assert.equal(editor.getModel()!.getLineContent(11), '// ciaociaociaociao');
|
||||
assert.strictEqual(editor.getModel()!.getLineContent(11), '// ciaociaociaociao');
|
||||
|
||||
findModel.dispose();
|
||||
findState.dispose();
|
||||
@@ -1578,10 +1578,10 @@ suite('FindModel', () => {
|
||||
null,
|
||||
[]
|
||||
);
|
||||
assert.equal(editor.getModel()!.getLineContent(11), '// <');
|
||||
assert.equal(editor.getModel()!.getLineContent(12), '\t><');
|
||||
assert.equal(editor.getModel()!.getLineContent(13), '\t><');
|
||||
assert.equal(editor.getModel()!.getLineContent(14), '\t>ciao');
|
||||
assert.strictEqual(editor.getModel()!.getLineContent(11), '// <');
|
||||
assert.strictEqual(editor.getModel()!.getLineContent(12), '\t><');
|
||||
assert.strictEqual(editor.getModel()!.getLineContent(13), '\t><');
|
||||
assert.strictEqual(editor.getModel()!.getLineContent(14), '\t>ciao');
|
||||
|
||||
findModel.dispose();
|
||||
findState.dispose();
|
||||
@@ -1610,8 +1610,8 @@ suite('FindModel', () => {
|
||||
[]
|
||||
);
|
||||
|
||||
assert.equal(editor.getModel()!.getLineContent(2), '#bar "cool.h"');
|
||||
assert.equal(editor.getModel()!.getLineContent(3), '#bar <iostream>');
|
||||
assert.strictEqual(editor.getModel()!.getLineContent(2), '#bar "cool.h"');
|
||||
assert.strictEqual(editor.getModel()!.getLineContent(3), '#bar <iostream>');
|
||||
|
||||
findModel.dispose();
|
||||
findState.dispose();
|
||||
@@ -1665,7 +1665,7 @@ suite('FindModel', () => {
|
||||
|
||||
findModel.selectAllMatches();
|
||||
|
||||
assert.deepEqual(editor!.getSelections()!.map(s => s.toString()), [
|
||||
assert.deepStrictEqual(editor!.getSelections()!.map(s => s.toString()), [
|
||||
new Selection(6, 14, 6, 19),
|
||||
new Selection(6, 27, 6, 32),
|
||||
new Selection(7, 14, 7, 19),
|
||||
@@ -1709,14 +1709,14 @@ suite('FindModel', () => {
|
||||
|
||||
findModel.selectAllMatches();
|
||||
|
||||
assert.deepEqual(editor!.getSelections()!.map(s => s.toString()), [
|
||||
assert.deepStrictEqual(editor!.getSelections()!.map(s => s.toString()), [
|
||||
new Selection(7, 14, 7, 19),
|
||||
new Selection(6, 14, 6, 19),
|
||||
new Selection(6, 27, 6, 32),
|
||||
new Selection(8, 14, 8, 19)
|
||||
].map(s => s.toString()));
|
||||
|
||||
assert.deepEqual(editor!.getSelection()!.toString(), new Selection(7, 14, 7, 19).toString());
|
||||
assert.deepStrictEqual(editor!.getSelection()!.toString(), new Selection(7, 14, 7, 19).toString());
|
||||
|
||||
assertFindState(
|
||||
editor,
|
||||
@@ -1800,7 +1800,7 @@ suite('FindModel', () => {
|
||||
[8, 14, 8, 19]
|
||||
]
|
||||
);
|
||||
assert.equal(editor.getModel()!.getLineContent(6), ' cout << "hello world, Hello!" << endl;');
|
||||
assert.strictEqual(editor.getModel()!.getLineContent(6), ' cout << "hello world, Hello!" << endl;');
|
||||
|
||||
findModel.replace();
|
||||
assertFindState(
|
||||
@@ -1812,7 +1812,7 @@ suite('FindModel', () => {
|
||||
[8, 14, 8, 19]
|
||||
]
|
||||
);
|
||||
assert.equal(editor.getModel()!.getLineContent(6), ' cout << "hi world, Hello!" << endl;');
|
||||
assert.strictEqual(editor.getModel()!.getLineContent(6), ' cout << "hi world, Hello!" << endl;');
|
||||
|
||||
findModel.replace();
|
||||
assertFindState(
|
||||
@@ -1823,7 +1823,7 @@ suite('FindModel', () => {
|
||||
[8, 14, 8, 19]
|
||||
]
|
||||
);
|
||||
assert.equal(editor.getModel()!.getLineContent(7), ' cout << "hi world again" << endl;');
|
||||
assert.strictEqual(editor.getModel()!.getLineContent(7), ' cout << "hi world again" << endl;');
|
||||
|
||||
findModel.replace();
|
||||
assertFindState(
|
||||
@@ -1832,7 +1832,7 @@ suite('FindModel', () => {
|
||||
null,
|
||||
[]
|
||||
);
|
||||
assert.equal(editor.getModel()!.getLineContent(8), ' cout << "hi world again" << endl;');
|
||||
assert.strictEqual(editor.getModel()!.getLineContent(8), ' cout << "hi world again" << endl;');
|
||||
|
||||
findModel.dispose();
|
||||
findState.dispose();
|
||||
@@ -1871,7 +1871,7 @@ suite('FindModel', () => {
|
||||
]
|
||||
);
|
||||
|
||||
assert.equal(editor.getModel()!.getLineContent(8), ' cout << "Hello world again" << endl;');
|
||||
assert.strictEqual(editor.getModel()!.getLineContent(8), ' cout << "Hello world again" << endl;');
|
||||
|
||||
findModel.replace();
|
||||
assertFindState(
|
||||
@@ -1883,7 +1883,7 @@ suite('FindModel', () => {
|
||||
[7, 14, 7, 19],
|
||||
]
|
||||
);
|
||||
assert.equal(editor.getModel()!.getLineContent(8), ' cout << "hi world again" << endl;');
|
||||
assert.strictEqual(editor.getModel()!.getLineContent(8), ' cout << "hi world again" << endl;');
|
||||
|
||||
findModel.replace();
|
||||
assertFindState(
|
||||
@@ -1894,7 +1894,7 @@ suite('FindModel', () => {
|
||||
[7, 14, 7, 19]
|
||||
]
|
||||
);
|
||||
assert.equal(editor.getModel()!.getLineContent(6), ' cout << "hi world, Hello!" << endl;');
|
||||
assert.strictEqual(editor.getModel()!.getLineContent(6), ' cout << "hi world, Hello!" << endl;');
|
||||
|
||||
findModel.replace();
|
||||
assertFindState(
|
||||
@@ -1903,7 +1903,7 @@ suite('FindModel', () => {
|
||||
null,
|
||||
[]
|
||||
);
|
||||
assert.equal(editor.getModel()!.getLineContent(7), ' cout << "hi world again" << endl;');
|
||||
assert.strictEqual(editor.getModel()!.getLineContent(7), ' cout << "hi world again" << endl;');
|
||||
|
||||
findModel.dispose();
|
||||
findState.dispose();
|
||||
@@ -1927,9 +1927,9 @@ suite('FindModel', () => {
|
||||
|
||||
findModel.replaceAll();
|
||||
|
||||
assert.equal(editor.getModel()!.getLineContent(6), ' cout << "hi world, Hello!" << endl;');
|
||||
assert.equal(editor.getModel()!.getLineContent(7), ' cout << "hi world again" << endl;');
|
||||
assert.equal(editor.getModel()!.getLineContent(8), ' cout << "hi world again" << endl;');
|
||||
assert.strictEqual(editor.getModel()!.getLineContent(6), ' cout << "hi world, Hello!" << endl;');
|
||||
assert.strictEqual(editor.getModel()!.getLineContent(7), ' cout << "hi world again" << endl;');
|
||||
assert.strictEqual(editor.getModel()!.getLineContent(8), ' cout << "hi world again" << endl;');
|
||||
|
||||
assertFindState(
|
||||
editor,
|
||||
@@ -1970,7 +1970,7 @@ suite('FindModel', () => {
|
||||
[8, 14, 8, 19]
|
||||
]
|
||||
);
|
||||
assert.equal(editor.getModel()!.getLineContent(6), ' cout << "hello world, Hello!" << endl;');
|
||||
assert.strictEqual(editor.getModel()!.getLineContent(6), ' cout << "hello world, Hello!" << endl;');
|
||||
|
||||
findModel.replace();
|
||||
assertFindState(
|
||||
@@ -1982,7 +1982,7 @@ suite('FindModel', () => {
|
||||
[8, 14, 8, 19]
|
||||
]
|
||||
);
|
||||
assert.equal(editor.getModel()!.getLineContent(6), ' cout << "hilo world, Hello!" << endl;');
|
||||
assert.strictEqual(editor.getModel()!.getLineContent(6), ' cout << "hilo world, Hello!" << endl;');
|
||||
|
||||
findModel.replace();
|
||||
assertFindState(
|
||||
@@ -1993,7 +1993,7 @@ suite('FindModel', () => {
|
||||
[8, 14, 8, 19]
|
||||
]
|
||||
);
|
||||
assert.equal(editor.getModel()!.getLineContent(7), ' cout << "hilo world again" << endl;');
|
||||
assert.strictEqual(editor.getModel()!.getLineContent(7), ' cout << "hilo world again" << endl;');
|
||||
|
||||
findModel.replace();
|
||||
assertFindState(
|
||||
@@ -2002,7 +2002,7 @@ suite('FindModel', () => {
|
||||
null,
|
||||
[]
|
||||
);
|
||||
assert.equal(editor.getModel()!.getLineContent(8), ' cout << "hilo world again" << endl;');
|
||||
assert.strictEqual(editor.getModel()!.getLineContent(8), ' cout << "hilo world again" << endl;');
|
||||
|
||||
findModel.dispose();
|
||||
findState.dispose();
|
||||
@@ -2027,10 +2027,10 @@ suite('FindModel', () => {
|
||||
|
||||
findModel.replaceAll();
|
||||
|
||||
assert.equal(editor.getModel()!.getLineContent(6), ' cout << "hello girl, Hello!" << endl;');
|
||||
assert.equal(editor.getModel()!.getLineContent(7), ' cout << "hello girl again" << endl;');
|
||||
assert.equal(editor.getModel()!.getLineContent(8), ' cout << "Hello girl again" << endl;');
|
||||
assert.equal(editor.getModel()!.getLineContent(9), ' cout << "hellogirl again" << endl;');
|
||||
assert.strictEqual(editor.getModel()!.getLineContent(6), ' cout << "hello girl, Hello!" << endl;');
|
||||
assert.strictEqual(editor.getModel()!.getLineContent(7), ' cout << "hello girl again" << endl;');
|
||||
assert.strictEqual(editor.getModel()!.getLineContent(8), ' cout << "Hello girl again" << endl;');
|
||||
assert.strictEqual(editor.getModel()!.getLineContent(9), ' cout << "hellogirl again" << endl;');
|
||||
|
||||
assertFindState(
|
||||
editor,
|
||||
@@ -2060,8 +2060,8 @@ suite('FindModel', () => {
|
||||
|
||||
findModel.replaceAll();
|
||||
|
||||
assert.equal(editor.getModel()!.getLineContent(6), ' cout << "hello girl, Hello!" << endl;');
|
||||
assert.equal(editor.getModel()!.getLineContent(8), ' cout << "Hello girl again" << endl;');
|
||||
assert.strictEqual(editor.getModel()!.getLineContent(6), ' cout << "hello girl, Hello!" << endl;');
|
||||
assert.strictEqual(editor.getModel()!.getLineContent(8), ' cout << "Hello girl again" << endl;');
|
||||
|
||||
assertFindState(
|
||||
editor,
|
||||
@@ -2094,10 +2094,10 @@ suite('FindModel', () => {
|
||||
|
||||
findModel.replaceAll();
|
||||
|
||||
assert.equal(editor.getModel()!.getLineContent(6), ' cout << "goodbye world, Goodbye!" << endl;');
|
||||
assert.equal(editor.getModel()!.getLineContent(7), ' cout << "goodbye world again" << endl;');
|
||||
assert.equal(editor.getModel()!.getLineContent(8), ' cout << "Goodbye world again" << endl;');
|
||||
assert.equal(editor.getModel()!.getLineContent(9), ' cout << "goodbyeworld again" << endl;');
|
||||
assert.strictEqual(editor.getModel()!.getLineContent(6), ' cout << "goodbye world, Goodbye!" << endl;');
|
||||
assert.strictEqual(editor.getModel()!.getLineContent(7), ' cout << "goodbye world again" << endl;');
|
||||
assert.strictEqual(editor.getModel()!.getLineContent(8), ' cout << "Goodbye world again" << endl;');
|
||||
assert.strictEqual(editor.getModel()!.getLineContent(9), ' cout << "goodbyeworld again" << endl;');
|
||||
|
||||
assertFindState(
|
||||
editor,
|
||||
@@ -2134,9 +2134,9 @@ suite('FindModel', () => {
|
||||
null,
|
||||
[]
|
||||
);
|
||||
assert.equal(editor.getModel()!.getLineContent(6), ' cout << " world, !" << endl;');
|
||||
assert.equal(editor.getModel()!.getLineContent(7), ' cout << " world again" << endl;');
|
||||
assert.equal(editor.getModel()!.getLineContent(8), ' cout << " world again" << endl;');
|
||||
assert.strictEqual(editor.getModel()!.getLineContent(6), ' cout << " world, !" << endl;');
|
||||
assert.strictEqual(editor.getModel()!.getLineContent(7), ' cout << " world again" << endl;');
|
||||
assert.strictEqual(editor.getModel()!.getLineContent(8), ' cout << " world again" << endl;');
|
||||
|
||||
findModel.dispose();
|
||||
findState.dispose();
|
||||
@@ -2159,7 +2159,7 @@ suite('FindModel', () => {
|
||||
expectedText += 'a line' + i + '\n';
|
||||
}
|
||||
expectedText += 'a ';
|
||||
assert.equal(editor!.getModel()!.getValue(), expectedText);
|
||||
assert.strictEqual(editor!.getModel()!.getValue(), expectedText);
|
||||
|
||||
findModel.dispose();
|
||||
findState.dispose();
|
||||
@@ -2188,9 +2188,9 @@ suite('FindModel', () => {
|
||||
null,
|
||||
[]
|
||||
);
|
||||
assert.equal(editor.getModel()!.getLineContent(6), ' cout << "hi world, Hello!" << endl;');
|
||||
assert.equal(editor.getModel()!.getLineContent(7), ' cout << "hi world again" << endl;');
|
||||
assert.equal(editor.getModel()!.getLineContent(9), ' cout << "hiworld again" << endl;');
|
||||
assert.strictEqual(editor.getModel()!.getLineContent(6), ' cout << "hi world, Hello!" << endl;');
|
||||
assert.strictEqual(editor.getModel()!.getLineContent(7), ' cout << "hi world again" << endl;');
|
||||
assert.strictEqual(editor.getModel()!.getLineContent(9), ' cout << "hiworld again" << endl;');
|
||||
|
||||
findModel.dispose();
|
||||
findState.dispose();
|
||||
@@ -2219,78 +2219,78 @@ suite('FindModel', () => {
|
||||
findState.change({ searchString: 'hello', loop: false }, false);
|
||||
let findModel = new FindModelBoundToEditorModel(editor, findState);
|
||||
|
||||
assert.equal(findState.matchesCount, 5);
|
||||
assert.strictEqual(findState.matchesCount, 5);
|
||||
|
||||
// Test next operations
|
||||
assert.equal(findState.matchesPosition, 0);
|
||||
assert.equal(findState.canNavigateForward(), true);
|
||||
assert.equal(findState.canNavigateBack(), true);
|
||||
assert.strictEqual(findState.matchesPosition, 0);
|
||||
assert.strictEqual(findState.canNavigateForward(), true);
|
||||
assert.strictEqual(findState.canNavigateBack(), true);
|
||||
|
||||
findModel.moveToNextMatch();
|
||||
assert.equal(findState.matchesPosition, 1);
|
||||
assert.equal(findState.canNavigateForward(), true);
|
||||
assert.equal(findState.canNavigateBack(), false);
|
||||
assert.strictEqual(findState.matchesPosition, 1);
|
||||
assert.strictEqual(findState.canNavigateForward(), true);
|
||||
assert.strictEqual(findState.canNavigateBack(), false);
|
||||
|
||||
findModel.moveToNextMatch();
|
||||
assert.equal(findState.matchesPosition, 2);
|
||||
assert.equal(findState.canNavigateForward(), true);
|
||||
assert.equal(findState.canNavigateBack(), true);
|
||||
assert.strictEqual(findState.matchesPosition, 2);
|
||||
assert.strictEqual(findState.canNavigateForward(), true);
|
||||
assert.strictEqual(findState.canNavigateBack(), true);
|
||||
|
||||
findModel.moveToNextMatch();
|
||||
assert.equal(findState.matchesPosition, 3);
|
||||
assert.equal(findState.canNavigateForward(), true);
|
||||
assert.equal(findState.canNavigateBack(), true);
|
||||
assert.strictEqual(findState.matchesPosition, 3);
|
||||
assert.strictEqual(findState.canNavigateForward(), true);
|
||||
assert.strictEqual(findState.canNavigateBack(), true);
|
||||
|
||||
findModel.moveToNextMatch();
|
||||
assert.equal(findState.matchesPosition, 4);
|
||||
assert.equal(findState.canNavigateForward(), true);
|
||||
assert.equal(findState.canNavigateBack(), true);
|
||||
assert.strictEqual(findState.matchesPosition, 4);
|
||||
assert.strictEqual(findState.canNavigateForward(), true);
|
||||
assert.strictEqual(findState.canNavigateBack(), true);
|
||||
|
||||
findModel.moveToNextMatch();
|
||||
assert.equal(findState.matchesPosition, 5);
|
||||
assert.equal(findState.canNavigateForward(), false);
|
||||
assert.equal(findState.canNavigateBack(), true);
|
||||
assert.strictEqual(findState.matchesPosition, 5);
|
||||
assert.strictEqual(findState.canNavigateForward(), false);
|
||||
assert.strictEqual(findState.canNavigateBack(), true);
|
||||
|
||||
findModel.moveToNextMatch();
|
||||
assert.equal(findState.matchesPosition, 5);
|
||||
assert.equal(findState.canNavigateForward(), false);
|
||||
assert.equal(findState.canNavigateBack(), true);
|
||||
assert.strictEqual(findState.matchesPosition, 5);
|
||||
assert.strictEqual(findState.canNavigateForward(), false);
|
||||
assert.strictEqual(findState.canNavigateBack(), true);
|
||||
|
||||
findModel.moveToNextMatch();
|
||||
assert.equal(findState.matchesPosition, 5);
|
||||
assert.equal(findState.canNavigateForward(), false);
|
||||
assert.equal(findState.canNavigateBack(), true);
|
||||
assert.strictEqual(findState.matchesPosition, 5);
|
||||
assert.strictEqual(findState.canNavigateForward(), false);
|
||||
assert.strictEqual(findState.canNavigateBack(), true);
|
||||
|
||||
// Test previous operations
|
||||
findModel.moveToPrevMatch();
|
||||
assert.equal(findState.matchesPosition, 4);
|
||||
assert.equal(findState.canNavigateForward(), true);
|
||||
assert.equal(findState.canNavigateBack(), true);
|
||||
assert.strictEqual(findState.matchesPosition, 4);
|
||||
assert.strictEqual(findState.canNavigateForward(), true);
|
||||
assert.strictEqual(findState.canNavigateBack(), true);
|
||||
|
||||
findModel.moveToPrevMatch();
|
||||
assert.equal(findState.matchesPosition, 3);
|
||||
assert.equal(findState.canNavigateForward(), true);
|
||||
assert.equal(findState.canNavigateBack(), true);
|
||||
assert.strictEqual(findState.matchesPosition, 3);
|
||||
assert.strictEqual(findState.canNavigateForward(), true);
|
||||
assert.strictEqual(findState.canNavigateBack(), true);
|
||||
|
||||
findModel.moveToPrevMatch();
|
||||
assert.equal(findState.matchesPosition, 2);
|
||||
assert.equal(findState.canNavigateForward(), true);
|
||||
assert.equal(findState.canNavigateBack(), true);
|
||||
assert.strictEqual(findState.matchesPosition, 2);
|
||||
assert.strictEqual(findState.canNavigateForward(), true);
|
||||
assert.strictEqual(findState.canNavigateBack(), true);
|
||||
|
||||
findModel.moveToPrevMatch();
|
||||
assert.equal(findState.matchesPosition, 1);
|
||||
assert.equal(findState.canNavigateForward(), true);
|
||||
assert.equal(findState.canNavigateBack(), false);
|
||||
assert.strictEqual(findState.matchesPosition, 1);
|
||||
assert.strictEqual(findState.canNavigateForward(), true);
|
||||
assert.strictEqual(findState.canNavigateBack(), false);
|
||||
|
||||
findModel.moveToPrevMatch();
|
||||
assert.equal(findState.matchesPosition, 1);
|
||||
assert.equal(findState.canNavigateForward(), true);
|
||||
assert.equal(findState.canNavigateBack(), false);
|
||||
assert.strictEqual(findState.matchesPosition, 1);
|
||||
assert.strictEqual(findState.canNavigateForward(), true);
|
||||
assert.strictEqual(findState.canNavigateBack(), false);
|
||||
|
||||
findModel.moveToPrevMatch();
|
||||
assert.equal(findState.matchesPosition, 1);
|
||||
assert.equal(findState.canNavigateForward(), true);
|
||||
assert.equal(findState.canNavigateBack(), false);
|
||||
assert.strictEqual(findState.matchesPosition, 1);
|
||||
assert.strictEqual(findState.canNavigateForward(), true);
|
||||
assert.strictEqual(findState.canNavigateBack(), false);
|
||||
|
||||
});
|
||||
|
||||
@@ -2299,78 +2299,78 @@ suite('FindModel', () => {
|
||||
findState.change({ searchString: 'hello' }, false);
|
||||
let findModel = new FindModelBoundToEditorModel(editor, findState);
|
||||
|
||||
assert.equal(findState.matchesCount, 5);
|
||||
assert.strictEqual(findState.matchesCount, 5);
|
||||
|
||||
// Test next operations
|
||||
assert.equal(findState.matchesPosition, 0);
|
||||
assert.equal(findState.canNavigateForward(), true);
|
||||
assert.equal(findState.canNavigateBack(), true);
|
||||
assert.strictEqual(findState.matchesPosition, 0);
|
||||
assert.strictEqual(findState.canNavigateForward(), true);
|
||||
assert.strictEqual(findState.canNavigateBack(), true);
|
||||
|
||||
findModel.moveToNextMatch();
|
||||
assert.equal(findState.matchesPosition, 1);
|
||||
assert.equal(findState.canNavigateForward(), true);
|
||||
assert.equal(findState.canNavigateBack(), true);
|
||||
assert.strictEqual(findState.matchesPosition, 1);
|
||||
assert.strictEqual(findState.canNavigateForward(), true);
|
||||
assert.strictEqual(findState.canNavigateBack(), true);
|
||||
|
||||
findModel.moveToNextMatch();
|
||||
assert.equal(findState.matchesPosition, 2);
|
||||
assert.equal(findState.canNavigateForward(), true);
|
||||
assert.equal(findState.canNavigateBack(), true);
|
||||
assert.strictEqual(findState.matchesPosition, 2);
|
||||
assert.strictEqual(findState.canNavigateForward(), true);
|
||||
assert.strictEqual(findState.canNavigateBack(), true);
|
||||
|
||||
findModel.moveToNextMatch();
|
||||
assert.equal(findState.matchesPosition, 3);
|
||||
assert.equal(findState.canNavigateForward(), true);
|
||||
assert.equal(findState.canNavigateBack(), true);
|
||||
assert.strictEqual(findState.matchesPosition, 3);
|
||||
assert.strictEqual(findState.canNavigateForward(), true);
|
||||
assert.strictEqual(findState.canNavigateBack(), true);
|
||||
|
||||
findModel.moveToNextMatch();
|
||||
assert.equal(findState.matchesPosition, 4);
|
||||
assert.equal(findState.canNavigateForward(), true);
|
||||
assert.equal(findState.canNavigateBack(), true);
|
||||
assert.strictEqual(findState.matchesPosition, 4);
|
||||
assert.strictEqual(findState.canNavigateForward(), true);
|
||||
assert.strictEqual(findState.canNavigateBack(), true);
|
||||
|
||||
findModel.moveToNextMatch();
|
||||
assert.equal(findState.matchesPosition, 5);
|
||||
assert.equal(findState.canNavigateForward(), true);
|
||||
assert.equal(findState.canNavigateBack(), true);
|
||||
assert.strictEqual(findState.matchesPosition, 5);
|
||||
assert.strictEqual(findState.canNavigateForward(), true);
|
||||
assert.strictEqual(findState.canNavigateBack(), true);
|
||||
|
||||
findModel.moveToNextMatch();
|
||||
assert.equal(findState.matchesPosition, 1);
|
||||
assert.equal(findState.canNavigateForward(), true);
|
||||
assert.equal(findState.canNavigateBack(), true);
|
||||
assert.strictEqual(findState.matchesPosition, 1);
|
||||
assert.strictEqual(findState.canNavigateForward(), true);
|
||||
assert.strictEqual(findState.canNavigateBack(), true);
|
||||
|
||||
findModel.moveToNextMatch();
|
||||
assert.equal(findState.matchesPosition, 2);
|
||||
assert.equal(findState.canNavigateForward(), true);
|
||||
assert.equal(findState.canNavigateBack(), true);
|
||||
assert.strictEqual(findState.matchesPosition, 2);
|
||||
assert.strictEqual(findState.canNavigateForward(), true);
|
||||
assert.strictEqual(findState.canNavigateBack(), true);
|
||||
|
||||
// Test previous operations
|
||||
findModel.moveToPrevMatch();
|
||||
assert.equal(findState.matchesPosition, 1);
|
||||
assert.equal(findState.canNavigateForward(), true);
|
||||
assert.equal(findState.canNavigateBack(), true);
|
||||
assert.strictEqual(findState.matchesPosition, 1);
|
||||
assert.strictEqual(findState.canNavigateForward(), true);
|
||||
assert.strictEqual(findState.canNavigateBack(), true);
|
||||
|
||||
findModel.moveToPrevMatch();
|
||||
assert.equal(findState.matchesPosition, 5);
|
||||
assert.equal(findState.canNavigateForward(), true);
|
||||
assert.equal(findState.canNavigateBack(), true);
|
||||
assert.strictEqual(findState.matchesPosition, 5);
|
||||
assert.strictEqual(findState.canNavigateForward(), true);
|
||||
assert.strictEqual(findState.canNavigateBack(), true);
|
||||
|
||||
findModel.moveToPrevMatch();
|
||||
assert.equal(findState.matchesPosition, 4);
|
||||
assert.equal(findState.canNavigateForward(), true);
|
||||
assert.equal(findState.canNavigateBack(), true);
|
||||
assert.strictEqual(findState.matchesPosition, 4);
|
||||
assert.strictEqual(findState.canNavigateForward(), true);
|
||||
assert.strictEqual(findState.canNavigateBack(), true);
|
||||
|
||||
findModel.moveToPrevMatch();
|
||||
assert.equal(findState.matchesPosition, 3);
|
||||
assert.equal(findState.canNavigateForward(), true);
|
||||
assert.equal(findState.canNavigateBack(), true);
|
||||
assert.strictEqual(findState.matchesPosition, 3);
|
||||
assert.strictEqual(findState.canNavigateForward(), true);
|
||||
assert.strictEqual(findState.canNavigateBack(), true);
|
||||
|
||||
findModel.moveToPrevMatch();
|
||||
assert.equal(findState.matchesPosition, 2);
|
||||
assert.equal(findState.canNavigateForward(), true);
|
||||
assert.equal(findState.canNavigateBack(), true);
|
||||
assert.strictEqual(findState.matchesPosition, 2);
|
||||
assert.strictEqual(findState.canNavigateForward(), true);
|
||||
assert.strictEqual(findState.canNavigateBack(), true);
|
||||
|
||||
findModel.moveToPrevMatch();
|
||||
assert.equal(findState.matchesPosition, 1);
|
||||
assert.equal(findState.canNavigateForward(), true);
|
||||
assert.equal(findState.canNavigateBack(), true);
|
||||
assert.strictEqual(findState.matchesPosition, 1);
|
||||
assert.strictEqual(findState.canNavigateForward(), true);
|
||||
assert.strictEqual(findState.canNavigateBack(), true);
|
||||
|
||||
});
|
||||
|
||||
|
||||
@@ -13,7 +13,7 @@ suite('Replace Pattern test', () => {
|
||||
let testParse = (input: string, expectedPieces: ReplacePiece[]) => {
|
||||
let actual = parseReplaceString(input);
|
||||
let expected = new ReplacePattern(expectedPieces);
|
||||
assert.deepEqual(actual, expected, 'Parsing ' + input);
|
||||
assert.deepStrictEqual(actual, expected, 'Parsing ' + input);
|
||||
};
|
||||
|
||||
// no backslash => no treatment
|
||||
@@ -73,14 +73,14 @@ suite('Replace Pattern test', () => {
|
||||
let testParse = (input: string, expectedPieces: ReplacePiece[]) => {
|
||||
let actual = parseReplaceString(input);
|
||||
let expected = new ReplacePattern(expectedPieces);
|
||||
assert.deepEqual(actual, expected, 'Parsing ' + input);
|
||||
assert.deepStrictEqual(actual, expected, 'Parsing ' + input);
|
||||
};
|
||||
function assertReplace(target: string, search: RegExp, replaceString: string, expected: string): void {
|
||||
let replacePattern = parseReplaceString(replaceString);
|
||||
let m = search.exec(target);
|
||||
let actual = replacePattern.buildReplaceString(m);
|
||||
|
||||
assert.equal(actual, expected, `${target}.replace(${search}, ${replaceString}) === ${expected}`);
|
||||
assert.strictEqual(actual, expected, `${target}.replace(${search}, ${replaceString}) === ${expected}`);
|
||||
}
|
||||
|
||||
// \U, \u => uppercase \L, \l => lowercase \E => cancel
|
||||
@@ -107,7 +107,7 @@ suite('Replace Pattern test', () => {
|
||||
let m = search.exec(target);
|
||||
let actual = replacePattern.buildReplaceString(m);
|
||||
|
||||
assert.deepEqual(actual, expected, `${target}.replace(${search}, ${replaceString})`);
|
||||
assert.deepStrictEqual(actual, expected, `${target}.replace(${search}, ${replaceString})`);
|
||||
};
|
||||
|
||||
testJSReplaceSemantics('hi', /hi/, 'hello', 'hi'.replace(/hi/, 'hello'));
|
||||
@@ -136,7 +136,7 @@ suite('Replace Pattern test', () => {
|
||||
let m = search.exec(target);
|
||||
let actual = replacePattern.buildReplaceString(m);
|
||||
|
||||
assert.equal(actual, expected, `${target}.replace(${search}, ${replaceString}) === ${expected}`);
|
||||
assert.strictEqual(actual, expected, `${target}.replace(${search}, ${replaceString}) === ${expected}`);
|
||||
}
|
||||
|
||||
assertReplace('bla', /bla/, 'hello', 'hello');
|
||||
@@ -162,7 +162,7 @@ suite('Replace Pattern test', () => {
|
||||
let m = search.exec(target);
|
||||
let actual = replacePattern.buildReplaceString(m);
|
||||
|
||||
assert.equal(actual, expected, `${target}.replace(${search}, ${replaceString}) === ${expected}`);
|
||||
assert.strictEqual(actual, expected, `${target}.replace(${search}, ${replaceString}) === ${expected}`);
|
||||
}
|
||||
assertReplace('this is a bla text', /bla/, 'hello', 'hello');
|
||||
assertReplace('this is a bla text', /this(?=.*bla)/, 'that', 'that');
|
||||
@@ -184,14 +184,14 @@ suite('Replace Pattern test', () => {
|
||||
let replacePattern = parseReplaceString('a{$1}');
|
||||
let matches = /a(z)?/.exec('abcd');
|
||||
let actual = replacePattern.buildReplaceString(matches);
|
||||
assert.equal(actual, 'a{}');
|
||||
assert.strictEqual(actual, 'a{}');
|
||||
});
|
||||
|
||||
test('buildReplaceStringWithCasePreserved test', () => {
|
||||
function assertReplace(target: string[], replaceString: string, expected: string): void {
|
||||
let actual: string = '';
|
||||
actual = buildReplaceStringWithCasePreserved(target, replaceString);
|
||||
assert.equal(actual, expected);
|
||||
assert.strictEqual(actual, expected);
|
||||
}
|
||||
|
||||
assertReplace(['abc'], 'Def', 'def');
|
||||
@@ -219,7 +219,7 @@ suite('Replace Pattern test', () => {
|
||||
function assertReplace(target: string[], replaceString: string, expected: string): void {
|
||||
let replacePattern = parseReplaceString(replaceString);
|
||||
let actual = replacePattern.buildReplaceString(target, true);
|
||||
assert.equal(actual, expected);
|
||||
assert.strictEqual(actual, expected);
|
||||
}
|
||||
|
||||
assertReplace(['abc'], 'Def', 'def');
|
||||
|
||||
@@ -16,13 +16,12 @@ import { Color } from 'vs/base/common/color';
|
||||
import { ScrollableElement } from 'vs/base/browser/ui/scrollbar/scrollableElement';
|
||||
import { ScrollbarVisibility } from 'vs/base/common/scrollable';
|
||||
import { ScrollType } from 'vs/editor/common/editorCommon';
|
||||
import { getBaseLabel, getPathLabel } from 'vs/base/common/labels';
|
||||
import { getBaseLabel } from 'vs/base/common/labels';
|
||||
import { isNonEmptyArray } from 'vs/base/common/arrays';
|
||||
import { Event, Emitter } from 'vs/base/common/event';
|
||||
import { PeekViewWidget, peekViewTitleForeground, peekViewTitleInfoForeground } from 'vs/editor/contrib/peekView/peekView';
|
||||
import { basename } from 'vs/base/common/resources';
|
||||
import { IAction } from 'vs/base/common/actions';
|
||||
import { IActionBarOptions, ActionsOrientation } from 'vs/base/browser/ui/actionbar/actionbar';
|
||||
import { SeverityIcon } from 'vs/platform/severityIcon/common/severityIcon';
|
||||
import { EditorOption } from 'vs/editor/common/config/editorOptions';
|
||||
import { IOpenerService } from 'vs/platform/opener/common/opener';
|
||||
@@ -31,6 +30,7 @@ import { IContextKeyService } from 'vs/platform/contextkey/common/contextkey';
|
||||
import { createAndFillInActionBarActions } from 'vs/platform/actions/browser/menuEntryActionViewItem';
|
||||
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
|
||||
import { splitLines } from 'vs/base/common/strings';
|
||||
import { ILabelService } from 'vs/platform/label/common/label';
|
||||
|
||||
class MessageWidget {
|
||||
|
||||
@@ -51,6 +51,7 @@ class MessageWidget {
|
||||
editor: ICodeEditor,
|
||||
onRelatedInformation: (related: IRelatedInformation) => void,
|
||||
private readonly _openerService: IOpenerService,
|
||||
private readonly _labelService: ILabelService
|
||||
) {
|
||||
this._editor = editor;
|
||||
|
||||
@@ -169,7 +170,7 @@ class MessageWidget {
|
||||
let relatedResource = document.createElement('a');
|
||||
relatedResource.classList.add('filename');
|
||||
relatedResource.innerText = `${getBaseLabel(related.resource)}(${related.startLineNumber}, ${related.startColumn}): `;
|
||||
relatedResource.title = getPathLabel(related.resource, undefined);
|
||||
relatedResource.title = this._labelService.getUriLabel(related.resource);
|
||||
this._relatedDiagnostics.set(relatedResource, related);
|
||||
|
||||
let relatedMessage = document.createElement('span');
|
||||
@@ -248,7 +249,8 @@ export class MarkerNavigationWidget extends PeekViewWidget {
|
||||
@IOpenerService private readonly _openerService: IOpenerService,
|
||||
@IMenuService private readonly _menuService: IMenuService,
|
||||
@IInstantiationService instantiationService: IInstantiationService,
|
||||
@IContextKeyService private readonly _contextKeyService: IContextKeyService
|
||||
@IContextKeyService private readonly _contextKeyService: IContextKeyService,
|
||||
@ILabelService private readonly _labelService: ILabelService
|
||||
) {
|
||||
super(editor, { showArrow: true, showFrame: true, isAccessible: true }, instantiationService);
|
||||
this._severity = MarkerSeverity.Warning;
|
||||
@@ -310,13 +312,6 @@ export class MarkerNavigationWidget extends PeekViewWidget {
|
||||
this._icon = dom.append(container, dom.$(''));
|
||||
}
|
||||
|
||||
protected _getActionBarOptions(): IActionBarOptions {
|
||||
return {
|
||||
...super._getActionBarOptions(),
|
||||
orientation: ActionsOrientation.HORIZONTAL
|
||||
};
|
||||
}
|
||||
|
||||
protected _fillBody(container: HTMLElement): void {
|
||||
this._parentContainer = container;
|
||||
container.classList.add('marker-widget');
|
||||
@@ -326,7 +321,7 @@ export class MarkerNavigationWidget extends PeekViewWidget {
|
||||
this._container = document.createElement('div');
|
||||
container.appendChild(this._container);
|
||||
|
||||
this._message = new MessageWidget(this._container, this.editor, related => this._onDidSelectRelatedInformation.fire(related), this._openerService);
|
||||
this._message = new MessageWidget(this._container, this.editor, related => this._onDidSelectRelatedInformation.fire(related), this._openerService, this._labelService);
|
||||
this._disposables.add(this._message);
|
||||
}
|
||||
|
||||
|
||||
@@ -51,7 +51,7 @@ export class OneReference {
|
||||
);
|
||||
} else {
|
||||
return localize(
|
||||
'aria.oneReference.preview', "symbol in {0} on line {1} at column {2}, {3}",
|
||||
{ key: 'aria.oneReference.preview', comment: ['Placeholders are: 0: filename, 1:line number, 2: column number, 3: preview snippet of source code'] }, "symbol in {0} on line {1} at column {2}, {3}",
|
||||
basename(this.uri), this.range.startLineNumber, this.range.startColumn, preview.value
|
||||
);
|
||||
}
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
import * as nls from 'vs/nls';
|
||||
import { IKeyboardEvent } from 'vs/base/browser/keyboardEvent';
|
||||
import { KeyChord, KeyCode, KeyMod } from 'vs/base/common/keyCodes';
|
||||
import { IDisposable, DisposableStore, MutableDisposable } from 'vs/base/common/lifecycle';
|
||||
import { IDisposable, DisposableStore } from 'vs/base/common/lifecycle';
|
||||
import { IEmptyContentData } from 'vs/editor/browser/controller/mouseTarget';
|
||||
import { ICodeEditor, IEditorMouseEvent, MouseTargetType } from 'vs/editor/browser/editorBrowser';
|
||||
import { EditorAction, ServicesAccessor, registerEditorAction, registerEditorContribution } from 'vs/editor/browser/editorExtensions';
|
||||
@@ -22,11 +22,10 @@ import { KeybindingWeight } from 'vs/platform/keybinding/common/keybindingsRegis
|
||||
import { IOpenerService } from 'vs/platform/opener/common/opener';
|
||||
import { editorHoverBackground, editorHoverBorder, editorHoverHighlight, textCodeBlockBackground, textLinkForeground, editorHoverStatusBarBackground, editorHoverForeground } from 'vs/platform/theme/common/colorRegistry';
|
||||
import { IThemeService, registerThemingParticipant } from 'vs/platform/theme/common/themeService';
|
||||
import { IMarkerDecorationsService } from 'vs/editor/common/services/markersDecorationService';
|
||||
import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding';
|
||||
import { AccessibilitySupport } from 'vs/platform/accessibility/common/accessibility';
|
||||
import { GotoDefinitionAtPositionEditorContribution } from 'vs/editor/contrib/gotoSymbol/link/goToDefinitionAtPosition';
|
||||
import { IContextKeyService, IContextKey } from 'vs/platform/contextkey/common/contextkey';
|
||||
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
|
||||
|
||||
export class ModesHoverController implements IEditorContribution {
|
||||
|
||||
@@ -35,22 +34,8 @@ export class ModesHoverController implements IEditorContribution {
|
||||
private readonly _toUnhook = new DisposableStore();
|
||||
private readonly _didChangeConfigurationHandler: IDisposable;
|
||||
|
||||
private readonly _contentWidget = new MutableDisposable<ModesContentHoverWidget>();
|
||||
private readonly _glyphWidget = new MutableDisposable<ModesGlyphHoverWidget>();
|
||||
|
||||
get contentWidget(): ModesContentHoverWidget {
|
||||
if (!this._contentWidget.value) {
|
||||
this._createHoverWidgets();
|
||||
}
|
||||
return this._contentWidget.value!;
|
||||
}
|
||||
|
||||
get glyphWidget(): ModesGlyphHoverWidget {
|
||||
if (!this._glyphWidget.value) {
|
||||
this._createHoverWidgets();
|
||||
}
|
||||
return this._glyphWidget.value!;
|
||||
}
|
||||
private _contentWidget: ModesContentHoverWidget | null;
|
||||
private _glyphWidget: ModesGlyphHoverWidget | null;
|
||||
|
||||
private _isMouseDown: boolean;
|
||||
private _hoverClicked: boolean;
|
||||
@@ -64,15 +49,16 @@ export class ModesHoverController implements IEditorContribution {
|
||||
}
|
||||
|
||||
constructor(private readonly _editor: ICodeEditor,
|
||||
@IInstantiationService private readonly _instantiationService: IInstantiationService,
|
||||
@IOpenerService private readonly _openerService: IOpenerService,
|
||||
@IModeService private readonly _modeService: IModeService,
|
||||
@IMarkerDecorationsService private readonly _markerDecorationsService: IMarkerDecorationsService,
|
||||
@IKeybindingService private readonly _keybindingService: IKeybindingService,
|
||||
@IThemeService private readonly _themeService: IThemeService,
|
||||
@IContextKeyService _contextKeyService: IContextKeyService
|
||||
) {
|
||||
this._isMouseDown = false;
|
||||
this._hoverClicked = false;
|
||||
this._contentWidget = null;
|
||||
this._glyphWidget = null;
|
||||
|
||||
this._hookEvents();
|
||||
|
||||
@@ -113,8 +99,8 @@ export class ModesHoverController implements IEditorContribution {
|
||||
}
|
||||
|
||||
private _onModelDecorationsChanged(): void {
|
||||
this.contentWidget.onModelDecorationsChanged();
|
||||
this.glyphWidget.onModelDecorationsChanged();
|
||||
this._contentWidget?.onModelDecorationsChanged();
|
||||
this._glyphWidget?.onModelDecorationsChanged();
|
||||
}
|
||||
|
||||
private _onEditorScrollChanged(e: IScrollEvent): void {
|
||||
@@ -153,7 +139,7 @@ export class ModesHoverController implements IEditorContribution {
|
||||
private _onEditorMouseMove(mouseEvent: IEditorMouseEvent): void {
|
||||
let targetType = mouseEvent.target.type;
|
||||
|
||||
if (this._isMouseDown && this._hoverClicked && this.contentWidget.isColorPickerVisible()) {
|
||||
if (this._isMouseDown && this._hoverClicked) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -162,10 +148,14 @@ export class ModesHoverController implements IEditorContribution {
|
||||
return;
|
||||
}
|
||||
|
||||
if (this._isHoverSticky && !mouseEvent.event.browserEvent.view?.getSelection()?.isCollapsed) {
|
||||
// selected text within content hover widget
|
||||
return;
|
||||
}
|
||||
|
||||
if (
|
||||
!this._isHoverSticky && targetType === MouseTargetType.CONTENT_WIDGET && mouseEvent.target.detail === ModesContentHoverWidget.ID
|
||||
&& this._contentWidget.value?.isColorPickerVisible()
|
||||
&& this._contentWidget?.isColorPickerVisible()
|
||||
) {
|
||||
// though the hover is not sticky, the color picker needs to.
|
||||
return;
|
||||
@@ -186,26 +176,31 @@ export class ModesHoverController implements IEditorContribution {
|
||||
}
|
||||
|
||||
if (targetType === MouseTargetType.CONTENT_TEXT) {
|
||||
this.glyphWidget.hide();
|
||||
this._glyphWidget?.hide();
|
||||
|
||||
if (this._isHoverEnabled && mouseEvent.target.range) {
|
||||
// TODO@rebornix. This should be removed if we move Color Picker out of Hover component.
|
||||
// Check if mouse is hovering on color decorator
|
||||
const hoverOnColorDecorator = [...mouseEvent.target.element?.classList.values() || []].find(className => className.startsWith('ced-colorBox'))
|
||||
&& mouseEvent.target.range.endColumn - mouseEvent.target.range.startColumn === 1;
|
||||
if (hoverOnColorDecorator) {
|
||||
// shift the mouse focus by one as color decorator is a `before` decoration of next character.
|
||||
this.contentWidget.startShowingAt(new Range(mouseEvent.target.range.startLineNumber, mouseEvent.target.range.startColumn + 1, mouseEvent.target.range.endLineNumber, mouseEvent.target.range.endColumn + 1), HoverStartMode.Delayed, false);
|
||||
} else {
|
||||
this.contentWidget.startShowingAt(mouseEvent.target.range, HoverStartMode.Delayed, false);
|
||||
const showAtRange = (
|
||||
hoverOnColorDecorator // shift the mouse focus by one as color decorator is a `before` decoration of next character.
|
||||
? new Range(mouseEvent.target.range.startLineNumber, mouseEvent.target.range.startColumn + 1, mouseEvent.target.range.endLineNumber, mouseEvent.target.range.endColumn + 1)
|
||||
: mouseEvent.target.range
|
||||
);
|
||||
if (!this._contentWidget) {
|
||||
this._contentWidget = new ModesContentHoverWidget(this._editor, this._hoverVisibleKey, this._instantiationService, this._themeService);
|
||||
}
|
||||
|
||||
this._contentWidget.startShowingAt(showAtRange, HoverStartMode.Delayed, false);
|
||||
}
|
||||
} else if (targetType === MouseTargetType.GUTTER_GLYPH_MARGIN) {
|
||||
this.contentWidget.hide();
|
||||
this._contentWidget?.hide();
|
||||
|
||||
if (this._isHoverEnabled && mouseEvent.target.position) {
|
||||
this.glyphWidget.startShowingAt(mouseEvent.target.position.lineNumber);
|
||||
if (!this._glyphWidget) {
|
||||
this._glyphWidget = new ModesGlyphHoverWidget(this._editor, this._modeService, this._openerService);
|
||||
}
|
||||
this._glyphWidget.startShowingAt(mouseEvent.target.position.lineNumber);
|
||||
}
|
||||
} else {
|
||||
this._hideWidgets();
|
||||
@@ -220,29 +215,32 @@ export class ModesHoverController implements IEditorContribution {
|
||||
}
|
||||
|
||||
private _hideWidgets(): void {
|
||||
if (!this._glyphWidget.value || !this._contentWidget.value || (this._isMouseDown && this._hoverClicked && this._contentWidget.value.isColorPickerVisible())) {
|
||||
if ((this._isMouseDown && this._hoverClicked && this._contentWidget?.isColorPickerVisible())) {
|
||||
return;
|
||||
}
|
||||
|
||||
this._glyphWidget.value.hide();
|
||||
this._contentWidget.value.hide();
|
||||
this._hoverClicked = false;
|
||||
this._glyphWidget?.hide();
|
||||
this._contentWidget?.hide();
|
||||
}
|
||||
|
||||
private _createHoverWidgets() {
|
||||
this._contentWidget.value = new ModesContentHoverWidget(this._editor, this._hoverVisibleKey, this._markerDecorationsService, this._keybindingService, this._themeService, this._modeService, this._openerService);
|
||||
this._glyphWidget.value = new ModesGlyphHoverWidget(this._editor, this._modeService, this._openerService);
|
||||
public isColorPickerVisible(): boolean {
|
||||
return this._contentWidget?.isColorPickerVisible() || false;
|
||||
}
|
||||
|
||||
public showContentHover(range: Range, mode: HoverStartMode, focus: boolean): void {
|
||||
this.contentWidget.startShowingAt(range, mode, focus);
|
||||
if (!this._contentWidget) {
|
||||
this._contentWidget = new ModesContentHoverWidget(this._editor, this._hoverVisibleKey, this._instantiationService, this._themeService);
|
||||
}
|
||||
this._contentWidget.startShowingAt(range, mode, focus);
|
||||
}
|
||||
|
||||
public dispose(): void {
|
||||
this._unhookEvents();
|
||||
this._toUnhook.dispose();
|
||||
this._didChangeConfigurationHandler.dispose();
|
||||
this._glyphWidget.dispose();
|
||||
this._contentWidget.dispose();
|
||||
this._glyphWidget?.dispose();
|
||||
this._contentWidget?.dispose();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -3,168 +3,9 @@
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { IKeyboardEvent } from 'vs/base/browser/keyboardEvent';
|
||||
import { Widget } from 'vs/base/browser/ui/widget';
|
||||
import { KeyCode } from 'vs/base/common/keyCodes';
|
||||
import { IContentWidget, ICodeEditor, IContentWidgetPosition, ContentWidgetPositionPreference, IOverlayWidget, IOverlayWidgetPosition } from 'vs/editor/browser/editorBrowser';
|
||||
import { ICodeEditor, IOverlayWidget, IOverlayWidgetPosition } from 'vs/editor/browser/editorBrowser';
|
||||
import { ConfigurationChangedEvent, EditorOption } from 'vs/editor/common/config/editorOptions';
|
||||
import { Position } from 'vs/editor/common/core/position';
|
||||
import { Range } from 'vs/editor/common/core/range';
|
||||
import { renderHoverAction, HoverWidget } from 'vs/base/browser/ui/hover/hoverWidget';
|
||||
import { IDisposable } from 'vs/base/common/lifecycle';
|
||||
import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding';
|
||||
import { IContextKey } from 'vs/platform/contextkey/common/contextkey';
|
||||
|
||||
export class ContentHoverWidget extends Widget implements IContentWidget {
|
||||
|
||||
protected readonly _hover: HoverWidget;
|
||||
private readonly _id: string;
|
||||
protected _editor: ICodeEditor;
|
||||
private _isVisible: boolean;
|
||||
protected _showAtPosition: Position | null;
|
||||
protected _showAtRange: Range | null;
|
||||
private _stoleFocus: boolean;
|
||||
|
||||
// Editor.IContentWidget.allowEditorOverflow
|
||||
public allowEditorOverflow = true;
|
||||
|
||||
protected get isVisible(): boolean {
|
||||
return this._isVisible;
|
||||
}
|
||||
|
||||
protected set isVisible(value: boolean) {
|
||||
this._isVisible = value;
|
||||
this._hover.containerDomNode.classList.toggle('hidden', !this._isVisible);
|
||||
}
|
||||
|
||||
constructor(
|
||||
id: string,
|
||||
editor: ICodeEditor,
|
||||
private readonly _hoverVisibleKey: IContextKey<boolean>,
|
||||
private readonly _keybindingService: IKeybindingService
|
||||
) {
|
||||
super();
|
||||
|
||||
this._hover = this._register(new HoverWidget());
|
||||
this._id = id;
|
||||
this._editor = editor;
|
||||
this._isVisible = false;
|
||||
this._stoleFocus = false;
|
||||
|
||||
this.onkeydown(this._hover.containerDomNode, (e: IKeyboardEvent) => {
|
||||
if (e.equals(KeyCode.Escape)) {
|
||||
this.hide();
|
||||
}
|
||||
});
|
||||
|
||||
this._register(this._editor.onDidChangeConfiguration((e: ConfigurationChangedEvent) => {
|
||||
if (e.hasChanged(EditorOption.fontInfo)) {
|
||||
this.updateFont();
|
||||
}
|
||||
}));
|
||||
|
||||
this._editor.onDidLayoutChange(e => this.layout());
|
||||
|
||||
this.layout();
|
||||
this._editor.addContentWidget(this);
|
||||
this._showAtPosition = null;
|
||||
this._showAtRange = null;
|
||||
this._stoleFocus = false;
|
||||
}
|
||||
|
||||
public getId(): string {
|
||||
return this._id;
|
||||
}
|
||||
|
||||
public getDomNode(): HTMLElement {
|
||||
return this._hover.containerDomNode;
|
||||
}
|
||||
|
||||
public showAt(position: Position, range: Range | null, focus: boolean): void {
|
||||
// Position has changed
|
||||
this._showAtPosition = position;
|
||||
this._showAtRange = range;
|
||||
this._hoverVisibleKey.set(true);
|
||||
this.isVisible = true;
|
||||
|
||||
this._editor.layoutContentWidget(this);
|
||||
// Simply force a synchronous render on the editor
|
||||
// such that the widget does not really render with left = '0px'
|
||||
this._editor.render();
|
||||
this._stoleFocus = focus;
|
||||
if (focus) {
|
||||
this._hover.containerDomNode.focus();
|
||||
}
|
||||
}
|
||||
|
||||
public hide(): void {
|
||||
if (!this.isVisible) {
|
||||
return;
|
||||
}
|
||||
|
||||
setTimeout(() => {
|
||||
// Give commands a chance to see the key
|
||||
if (!this.isVisible) {
|
||||
this._hoverVisibleKey.set(false);
|
||||
}
|
||||
}, 0);
|
||||
this.isVisible = false;
|
||||
|
||||
this._editor.layoutContentWidget(this);
|
||||
if (this._stoleFocus) {
|
||||
this._editor.focus();
|
||||
}
|
||||
}
|
||||
|
||||
public getPosition(): IContentWidgetPosition | null {
|
||||
if (this.isVisible) {
|
||||
return {
|
||||
position: this._showAtPosition,
|
||||
range: this._showAtRange,
|
||||
preference: [
|
||||
ContentWidgetPositionPreference.ABOVE,
|
||||
ContentWidgetPositionPreference.BELOW
|
||||
]
|
||||
};
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public dispose(): void {
|
||||
this._editor.removeContentWidget(this);
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
private updateFont(): void {
|
||||
const codeClasses: HTMLElement[] = Array.prototype.slice.call(this._hover.contentsDomNode.getElementsByClassName('code'));
|
||||
codeClasses.forEach(node => this._editor.applyFontInfo(node));
|
||||
}
|
||||
|
||||
protected updateContents(node: Node): void {
|
||||
this._hover.contentsDomNode.textContent = '';
|
||||
this._hover.contentsDomNode.appendChild(node);
|
||||
this.updateFont();
|
||||
|
||||
this._editor.layoutContentWidget(this);
|
||||
this._hover.onContentsChanged();
|
||||
}
|
||||
|
||||
protected _renderAction(parent: HTMLElement, actionOptions: { label: string, iconClass?: string, run: (target: HTMLElement) => void, commandId: string }): IDisposable {
|
||||
const keybinding = this._keybindingService.lookupKeybinding(actionOptions.commandId);
|
||||
const keybindingLabel = keybinding ? keybinding.getLabel() : null;
|
||||
return renderHoverAction(parent, actionOptions, keybindingLabel);
|
||||
}
|
||||
|
||||
private layout(): void {
|
||||
const height = Math.max(this._editor.getLayoutInfo().height / 4, 250);
|
||||
const { fontSize, lineHeight } = this._editor.getOption(EditorOption.fontInfo);
|
||||
|
||||
this._hover.contentsDomNode.style.fontSize = `${fontSize}px`;
|
||||
this._hover.contentsDomNode.style.lineHeight = `${lineHeight}px`;
|
||||
this._hover.contentsDomNode.style.maxHeight = `${height}px`;
|
||||
this._hover.contentsDomNode.style.maxWidth = `${Math.max(this._editor.getLayoutInfo().width * 0.66, 500)}px`;
|
||||
}
|
||||
}
|
||||
|
||||
export class GlyphHoverWidget extends Widget implements IOverlayWidget {
|
||||
|
||||
|
||||
@@ -0,0 +1,126 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import * as nls from 'vs/nls';
|
||||
import * as dom from 'vs/base/browser/dom';
|
||||
import { IMarkdownString, MarkdownString, isEmptyMarkdownString, markedStringsEquals } from 'vs/base/common/htmlContent';
|
||||
import { IDisposable, DisposableStore } from 'vs/base/common/lifecycle';
|
||||
import { ICodeEditor } from 'vs/editor/browser/editorBrowser';
|
||||
import { Range } from 'vs/editor/common/core/range';
|
||||
import { MarkdownRenderer } from 'vs/editor/browser/core/markdownRenderer';
|
||||
import { asArray } from 'vs/base/common/arrays';
|
||||
import { IOpenerService } from 'vs/platform/opener/common/opener';
|
||||
import { IModeService } from 'vs/editor/common/services/modeService';
|
||||
import { IModelDecoration } from 'vs/editor/common/model';
|
||||
import { IEditorHover, IEditorHoverParticipant, IHoverPart } from 'vs/editor/contrib/hover/modesContentHover';
|
||||
import { HoverProviderRegistry } from 'vs/editor/common/modes';
|
||||
import { getHover } from 'vs/editor/contrib/hover/getHover';
|
||||
import { Position } from 'vs/editor/common/core/position';
|
||||
import { CancellationToken } from 'vs/base/common/cancellation';
|
||||
|
||||
const $ = dom.$;
|
||||
|
||||
export class MarkdownHover implements IHoverPart {
|
||||
|
||||
constructor(
|
||||
public readonly range: Range,
|
||||
public readonly contents: IMarkdownString[]
|
||||
) { }
|
||||
|
||||
public equals(other: IHoverPart): boolean {
|
||||
if (other instanceof MarkdownHover) {
|
||||
return markedStringsEquals(this.contents, other.contents);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
export class MarkdownHoverParticipant implements IEditorHoverParticipant<MarkdownHover> {
|
||||
|
||||
constructor(
|
||||
private readonly _editor: ICodeEditor,
|
||||
private readonly _hover: IEditorHover,
|
||||
@IModeService private readonly _modeService: IModeService,
|
||||
@IOpenerService private readonly _openerService: IOpenerService,
|
||||
) { }
|
||||
|
||||
public createLoadingMessage(range: Range): MarkdownHover {
|
||||
return new MarkdownHover(range, [new MarkdownString().appendText(nls.localize('modesContentHover.loading', "Loading..."))]);
|
||||
}
|
||||
|
||||
public computeSync(hoverRange: Range, lineDecorations: IModelDecoration[]): MarkdownHover[] {
|
||||
if (!this._editor.hasModel()) {
|
||||
return [];
|
||||
}
|
||||
|
||||
const model = this._editor.getModel();
|
||||
const lineNumber = hoverRange.startLineNumber;
|
||||
const maxColumn = model.getLineMaxColumn(lineNumber);
|
||||
const result: MarkdownHover[] = [];
|
||||
for (const d of lineDecorations) {
|
||||
const startColumn = (d.range.startLineNumber === lineNumber) ? d.range.startColumn : 1;
|
||||
const endColumn = (d.range.endLineNumber === lineNumber) ? d.range.endColumn : maxColumn;
|
||||
|
||||
const hoverMessage = d.options.hoverMessage;
|
||||
if (!hoverMessage || isEmptyMarkdownString(hoverMessage)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const range = new Range(hoverRange.startLineNumber, startColumn, hoverRange.startLineNumber, endColumn);
|
||||
result.push(new MarkdownHover(range, asArray(hoverMessage)));
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public async computeAsync(range: Range, token: CancellationToken): Promise<MarkdownHover[]> {
|
||||
if (!this._editor.hasModel() || !range) {
|
||||
return Promise.resolve([]);
|
||||
}
|
||||
|
||||
const model = this._editor.getModel();
|
||||
|
||||
if (!HoverProviderRegistry.has(model)) {
|
||||
return Promise.resolve([]);
|
||||
}
|
||||
|
||||
const hovers = await getHover(model, new Position(
|
||||
range.startLineNumber,
|
||||
range.startColumn
|
||||
), token);
|
||||
|
||||
const result: MarkdownHover[] = [];
|
||||
for (const hover of hovers) {
|
||||
if (isEmptyMarkdownString(hover.contents)) {
|
||||
continue;
|
||||
}
|
||||
const rng = hover.range ? Range.lift(hover.range) : range;
|
||||
result.push(new MarkdownHover(rng, hover.contents));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
public renderHoverParts(hoverParts: MarkdownHover[], fragment: DocumentFragment): IDisposable {
|
||||
const disposables = new DisposableStore();
|
||||
for (const hoverPart of hoverParts) {
|
||||
for (const contents of hoverPart.contents) {
|
||||
if (isEmptyMarkdownString(contents)) {
|
||||
continue;
|
||||
}
|
||||
const markdownHoverElement = $('div.hover-row.markdown-hover');
|
||||
const hoverContentsElement = dom.append(markdownHoverElement, $('div.hover-contents'));
|
||||
const renderer = disposables.add(new MarkdownRenderer({ editor: this._editor }, this._modeService, this._openerService));
|
||||
disposables.add(renderer.onDidRenderAsync(() => {
|
||||
hoverContentsElement.className = 'hover-contents code-hover-contents';
|
||||
this._hover.onContentsChanged();
|
||||
}));
|
||||
const renderedContents = disposables.add(renderer.render(contents));
|
||||
hoverContentsElement.appendChild(renderedContents.element);
|
||||
fragment.appendChild(markdownHoverElement);
|
||||
}
|
||||
}
|
||||
return disposables;
|
||||
}
|
||||
}
|
||||
257
lib/vscode/src/vs/editor/contrib/hover/markerHoverParticipant.ts
Normal file
257
lib/vscode/src/vs/editor/contrib/hover/markerHoverParticipant.ts
Normal file
@@ -0,0 +1,257 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import * as nls from 'vs/nls';
|
||||
import * as dom from 'vs/base/browser/dom';
|
||||
import { IDisposable, toDisposable, DisposableStore, Disposable } from 'vs/base/common/lifecycle';
|
||||
import { ICodeEditor } from 'vs/editor/browser/editorBrowser';
|
||||
import { Range } from 'vs/editor/common/core/range';
|
||||
import { CodeActionTriggerType } from 'vs/editor/common/modes';
|
||||
import { isNonEmptyArray } from 'vs/base/common/arrays';
|
||||
import { IMarker, IMarkerData, MarkerSeverity } from 'vs/platform/markers/common/markers';
|
||||
import { basename } from 'vs/base/common/resources';
|
||||
import { IMarkerDecorationsService } from 'vs/editor/common/services/markersDecorationService';
|
||||
import { onUnexpectedError } from 'vs/base/common/errors';
|
||||
import { IOpenerService } from 'vs/platform/opener/common/opener';
|
||||
import { MarkerController, NextMarkerAction } from 'vs/editor/contrib/gotoError/gotoError';
|
||||
import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding';
|
||||
import { CancelablePromise, createCancelablePromise, disposableTimeout } from 'vs/base/common/async';
|
||||
import { getCodeActions, CodeActionSet } from 'vs/editor/contrib/codeAction/codeAction';
|
||||
import { QuickFixAction, QuickFixController } from 'vs/editor/contrib/codeAction/codeActionCommands';
|
||||
import { CodeActionKind, CodeActionTrigger } from 'vs/editor/contrib/codeAction/types';
|
||||
import { IModelDecoration } from 'vs/editor/common/model';
|
||||
import { EditorOption } from 'vs/editor/common/config/editorOptions';
|
||||
import { Progress } from 'vs/platform/progress/common/progress';
|
||||
import { ITextEditorOptions } from 'vs/platform/editor/common/editor';
|
||||
import { renderHoverAction } from 'vs/base/browser/ui/hover/hoverWidget';
|
||||
import { IEditorHover, IEditorHoverParticipant, IHoverPart } from 'vs/editor/contrib/hover/modesContentHover';
|
||||
|
||||
const $ = dom.$;
|
||||
|
||||
export class MarkerHover implements IHoverPart {
|
||||
|
||||
constructor(
|
||||
public readonly range: Range,
|
||||
public readonly marker: IMarker,
|
||||
) { }
|
||||
|
||||
public equals(other: IHoverPart): boolean {
|
||||
if (other instanceof MarkerHover) {
|
||||
return IMarkerData.makeKey(this.marker) === IMarkerData.makeKey(other.marker);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
const markerCodeActionTrigger: CodeActionTrigger = {
|
||||
type: CodeActionTriggerType.Manual,
|
||||
filter: { include: CodeActionKind.QuickFix }
|
||||
};
|
||||
|
||||
export class MarkerHoverParticipant implements IEditorHoverParticipant<MarkerHover> {
|
||||
|
||||
private recentMarkerCodeActionsInfo: { marker: IMarker, hasCodeActions: boolean } | undefined = undefined;
|
||||
|
||||
constructor(
|
||||
private readonly _editor: ICodeEditor,
|
||||
private readonly _hover: IEditorHover,
|
||||
@IMarkerDecorationsService private readonly _markerDecorationsService: IMarkerDecorationsService,
|
||||
@IKeybindingService private readonly _keybindingService: IKeybindingService,
|
||||
@IOpenerService private readonly _openerService: IOpenerService,
|
||||
) { }
|
||||
|
||||
public computeSync(hoverRange: Range, lineDecorations: IModelDecoration[]): MarkerHover[] {
|
||||
if (!this._editor.hasModel()) {
|
||||
return [];
|
||||
}
|
||||
|
||||
const model = this._editor.getModel();
|
||||
const lineNumber = hoverRange.startLineNumber;
|
||||
const maxColumn = model.getLineMaxColumn(lineNumber);
|
||||
const result: MarkerHover[] = [];
|
||||
for (const d of lineDecorations) {
|
||||
const startColumn = (d.range.startLineNumber === lineNumber) ? d.range.startColumn : 1;
|
||||
const endColumn = (d.range.endLineNumber === lineNumber) ? d.range.endColumn : maxColumn;
|
||||
|
||||
const marker = this._markerDecorationsService.getMarker(model.uri, d);
|
||||
if (!marker) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const range = new Range(hoverRange.startLineNumber, startColumn, hoverRange.startLineNumber, endColumn);
|
||||
result.push(new MarkerHover(range, marker));
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public renderHoverParts(hoverParts: MarkerHover[], fragment: DocumentFragment): IDisposable {
|
||||
if (!hoverParts.length) {
|
||||
return Disposable.None;
|
||||
}
|
||||
const disposables = new DisposableStore();
|
||||
hoverParts.forEach(msg => fragment.appendChild(this.renderMarkerHover(msg, disposables)));
|
||||
const markerHoverForStatusbar = hoverParts.length === 1 ? hoverParts[0] : hoverParts.sort((a, b) => MarkerSeverity.compare(a.marker.severity, b.marker.severity))[0];
|
||||
fragment.appendChild(this.renderMarkerStatusbar(markerHoverForStatusbar, disposables));
|
||||
return disposables;
|
||||
}
|
||||
|
||||
private renderMarkerHover(markerHover: MarkerHover, disposables: DisposableStore): HTMLElement {
|
||||
const hoverElement = $('div.hover-row');
|
||||
const markerElement = dom.append(hoverElement, $('div.marker.hover-contents'));
|
||||
const { source, message, code, relatedInformation } = markerHover.marker;
|
||||
|
||||
this._editor.applyFontInfo(markerElement);
|
||||
const messageElement = dom.append(markerElement, $('span'));
|
||||
messageElement.style.whiteSpace = 'pre-wrap';
|
||||
messageElement.innerText = message;
|
||||
|
||||
if (source || code) {
|
||||
// Code has link
|
||||
if (code && typeof code !== 'string') {
|
||||
const sourceAndCodeElement = $('span');
|
||||
if (source) {
|
||||
const sourceElement = dom.append(sourceAndCodeElement, $('span'));
|
||||
sourceElement.innerText = source;
|
||||
}
|
||||
const codeLink = dom.append(sourceAndCodeElement, $('a.code-link'));
|
||||
codeLink.setAttribute('href', code.target.toString());
|
||||
|
||||
disposables.add(dom.addDisposableListener(codeLink, 'click', (e) => {
|
||||
this._openerService.open(code.target);
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
}));
|
||||
|
||||
const codeElement = dom.append(codeLink, $('span'));
|
||||
codeElement.innerText = code.value;
|
||||
|
||||
const detailsElement = dom.append(markerElement, sourceAndCodeElement);
|
||||
detailsElement.style.opacity = '0.6';
|
||||
detailsElement.style.paddingLeft = '6px';
|
||||
} else {
|
||||
const detailsElement = dom.append(markerElement, $('span'));
|
||||
detailsElement.style.opacity = '0.6';
|
||||
detailsElement.style.paddingLeft = '6px';
|
||||
detailsElement.innerText = source && code ? `${source}(${code})` : source ? source : `(${code})`;
|
||||
}
|
||||
}
|
||||
|
||||
if (isNonEmptyArray(relatedInformation)) {
|
||||
for (const { message, resource, startLineNumber, startColumn } of relatedInformation) {
|
||||
const relatedInfoContainer = dom.append(markerElement, $('div'));
|
||||
relatedInfoContainer.style.marginTop = '8px';
|
||||
const a = dom.append(relatedInfoContainer, $('a'));
|
||||
a.innerText = `${basename(resource)}(${startLineNumber}, ${startColumn}): `;
|
||||
a.style.cursor = 'pointer';
|
||||
disposables.add(dom.addDisposableListener(a, 'click', (e) => {
|
||||
e.stopPropagation();
|
||||
e.preventDefault();
|
||||
if (this._openerService) {
|
||||
this._openerService.open(resource, {
|
||||
fromUserGesture: true,
|
||||
editorOptions: <ITextEditorOptions>{ selection: { startLineNumber, startColumn } }
|
||||
}).catch(onUnexpectedError);
|
||||
}
|
||||
}));
|
||||
const messageElement = dom.append<HTMLAnchorElement>(relatedInfoContainer, $('span'));
|
||||
messageElement.innerText = message;
|
||||
this._editor.applyFontInfo(messageElement);
|
||||
}
|
||||
}
|
||||
|
||||
return hoverElement;
|
||||
}
|
||||
|
||||
private renderMarkerStatusbar(markerHover: MarkerHover, disposables: DisposableStore): HTMLElement {
|
||||
const hoverElement = $('div.hover-row.status-bar');
|
||||
const actionsElement = dom.append(hoverElement, $('div.actions'));
|
||||
if (markerHover.marker.severity === MarkerSeverity.Error || markerHover.marker.severity === MarkerSeverity.Warning || markerHover.marker.severity === MarkerSeverity.Info) {
|
||||
disposables.add(this.renderAction(actionsElement, {
|
||||
label: nls.localize('peek problem', "Peek Problem"),
|
||||
commandId: NextMarkerAction.ID,
|
||||
run: () => {
|
||||
this._hover.hide();
|
||||
MarkerController.get(this._editor).showAtMarker(markerHover.marker);
|
||||
this._editor.focus();
|
||||
}
|
||||
}));
|
||||
}
|
||||
|
||||
if (!this._editor.getOption(EditorOption.readOnly)) {
|
||||
const quickfixPlaceholderElement = dom.append(actionsElement, $('div'));
|
||||
if (this.recentMarkerCodeActionsInfo) {
|
||||
if (IMarkerData.makeKey(this.recentMarkerCodeActionsInfo.marker) === IMarkerData.makeKey(markerHover.marker)) {
|
||||
if (!this.recentMarkerCodeActionsInfo.hasCodeActions) {
|
||||
quickfixPlaceholderElement.textContent = nls.localize('noQuickFixes', "No quick fixes available");
|
||||
}
|
||||
} else {
|
||||
this.recentMarkerCodeActionsInfo = undefined;
|
||||
}
|
||||
}
|
||||
const updatePlaceholderDisposable = this.recentMarkerCodeActionsInfo && !this.recentMarkerCodeActionsInfo.hasCodeActions ? Disposable.None : disposables.add(disposableTimeout(() => quickfixPlaceholderElement.textContent = nls.localize('checkingForQuickFixes', "Checking for quick fixes..."), 200));
|
||||
if (!quickfixPlaceholderElement.textContent) {
|
||||
// Have some content in here to avoid flickering
|
||||
quickfixPlaceholderElement.textContent = String.fromCharCode(0xA0); //
|
||||
}
|
||||
const codeActionsPromise = this.getCodeActions(markerHover.marker);
|
||||
disposables.add(toDisposable(() => codeActionsPromise.cancel()));
|
||||
codeActionsPromise.then(actions => {
|
||||
updatePlaceholderDisposable.dispose();
|
||||
this.recentMarkerCodeActionsInfo = { marker: markerHover.marker, hasCodeActions: actions.validActions.length > 0 };
|
||||
|
||||
if (!this.recentMarkerCodeActionsInfo.hasCodeActions) {
|
||||
actions.dispose();
|
||||
quickfixPlaceholderElement.textContent = nls.localize('noQuickFixes', "No quick fixes available");
|
||||
return;
|
||||
}
|
||||
quickfixPlaceholderElement.style.display = 'none';
|
||||
|
||||
let showing = false;
|
||||
disposables.add(toDisposable(() => {
|
||||
if (!showing) {
|
||||
actions.dispose();
|
||||
}
|
||||
}));
|
||||
|
||||
disposables.add(this.renderAction(actionsElement, {
|
||||
label: nls.localize('quick fixes', "Quick Fix..."),
|
||||
commandId: QuickFixAction.Id,
|
||||
run: (target) => {
|
||||
showing = true;
|
||||
const controller = QuickFixController.get(this._editor);
|
||||
const elementPosition = dom.getDomNodePagePosition(target);
|
||||
// Hide the hover pre-emptively, otherwise the editor can close the code actions
|
||||
// context menu as well when using keyboard navigation
|
||||
this._hover.hide();
|
||||
controller.showCodeActions(markerCodeActionTrigger, actions, {
|
||||
x: elementPosition.left + 6,
|
||||
y: elementPosition.top + elementPosition.height + 6
|
||||
});
|
||||
}
|
||||
}));
|
||||
});
|
||||
}
|
||||
|
||||
return hoverElement;
|
||||
}
|
||||
|
||||
private renderAction(parent: HTMLElement, actionOptions: { label: string, iconClass?: string, run: (target: HTMLElement) => void, commandId: string }): IDisposable {
|
||||
const keybinding = this._keybindingService.lookupKeybinding(actionOptions.commandId);
|
||||
const keybindingLabel = keybinding ? keybinding.getLabel() : null;
|
||||
return renderHoverAction(parent, actionOptions, keybindingLabel);
|
||||
}
|
||||
|
||||
private getCodeActions(marker: IMarker): CancelablePromise<CodeActionSet> {
|
||||
return createCancelablePromise(cancellationToken => {
|
||||
return getCodeActions(
|
||||
this._editor.getModel()!,
|
||||
new Range(marker.startLineNumber, marker.startColumn, marker.endLineNumber, marker.endColumn),
|
||||
markerCodeActionTrigger,
|
||||
Progress.None,
|
||||
cancellationToken);
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -3,228 +3,242 @@
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import * as nls from 'vs/nls';
|
||||
import * as dom from 'vs/base/browser/dom';
|
||||
import { CancellationToken } from 'vs/base/common/cancellation';
|
||||
import { Color, RGBA } from 'vs/base/common/color';
|
||||
import { IMarkdownString, MarkdownString, isEmptyMarkdownString, markedStringsEquals } from 'vs/base/common/htmlContent';
|
||||
import { IDisposable, toDisposable, DisposableStore, combinedDisposable, MutableDisposable } from 'vs/base/common/lifecycle';
|
||||
import { ICodeEditor } from 'vs/editor/browser/editorBrowser';
|
||||
import { IDisposable, DisposableStore, combinedDisposable } from 'vs/base/common/lifecycle';
|
||||
import { ContentWidgetPositionPreference, ICodeEditor, IContentWidget, IContentWidgetPosition } from 'vs/editor/browser/editorBrowser';
|
||||
import { Position } from 'vs/editor/common/core/position';
|
||||
import { IRange, Range } from 'vs/editor/common/core/range';
|
||||
import { Range } from 'vs/editor/common/core/range';
|
||||
import { ModelDecorationOptions } from 'vs/editor/common/model/textModel';
|
||||
import { DocumentColorProvider, Hover as MarkdownHover, HoverProviderRegistry, IColor, TokenizationRegistry, CodeActionTriggerType } from 'vs/editor/common/modes';
|
||||
import { DocumentColorProvider, IColor, TokenizationRegistry } from 'vs/editor/common/modes';
|
||||
import { getColorPresentations } from 'vs/editor/contrib/colorPicker/color';
|
||||
import { ColorDetector } from 'vs/editor/contrib/colorPicker/colorDetector';
|
||||
import { ColorPickerModel } from 'vs/editor/contrib/colorPicker/colorPickerModel';
|
||||
import { ColorPickerWidget } from 'vs/editor/contrib/colorPicker/colorPickerWidget';
|
||||
import { getHover } from 'vs/editor/contrib/hover/getHover';
|
||||
import { HoverOperation, HoverStartMode, IHoverComputer } from 'vs/editor/contrib/hover/hoverOperation';
|
||||
import { ContentHoverWidget } from 'vs/editor/contrib/hover/hoverWidgets';
|
||||
import { MarkdownRenderer } from 'vs/editor/browser/core/markdownRenderer';
|
||||
import { IThemeService, registerThemingParticipant } from 'vs/platform/theme/common/themeService';
|
||||
import { coalesce, isNonEmptyArray, asArray } from 'vs/base/common/arrays';
|
||||
import { IMarker, IMarkerData, MarkerSeverity } from 'vs/platform/markers/common/markers';
|
||||
import { basename } from 'vs/base/common/resources';
|
||||
import { IMarkerDecorationsService } from 'vs/editor/common/services/markersDecorationService';
|
||||
import { onUnexpectedError } from 'vs/base/common/errors';
|
||||
import { IOpenerService, NullOpenerService } from 'vs/platform/opener/common/opener';
|
||||
import { MarkerController, NextMarkerAction } from 'vs/editor/contrib/gotoError/gotoError';
|
||||
import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding';
|
||||
import { CancelablePromise, createCancelablePromise, disposableTimeout } from 'vs/base/common/async';
|
||||
import { getCodeActions, CodeActionSet } from 'vs/editor/contrib/codeAction/codeAction';
|
||||
import { QuickFixAction, QuickFixController } from 'vs/editor/contrib/codeAction/codeActionCommands';
|
||||
import { CodeActionKind, CodeActionTrigger } from 'vs/editor/contrib/codeAction/types';
|
||||
import { IModeService } from 'vs/editor/common/services/modeService';
|
||||
import { IIdentifiedSingleEditOperation, TrackedRangeStickiness } from 'vs/editor/common/model';
|
||||
import { EditorOption } from 'vs/editor/common/config/editorOptions';
|
||||
import { coalesce } from 'vs/base/common/arrays';
|
||||
import { IIdentifiedSingleEditOperation, IModelDecoration, TrackedRangeStickiness } from 'vs/editor/common/model';
|
||||
import { ConfigurationChangedEvent, EditorOption } from 'vs/editor/common/config/editorOptions';
|
||||
import { Constants } from 'vs/base/common/uint';
|
||||
import { textLinkForeground } from 'vs/platform/theme/common/colorRegistry';
|
||||
import { Progress } from 'vs/platform/progress/common/progress';
|
||||
import { IContextKey } from 'vs/platform/contextkey/common/contextkey';
|
||||
import { IKeyboardEvent } from 'vs/base/browser/keyboardEvent';
|
||||
import { Widget } from 'vs/base/browser/ui/widget';
|
||||
import { KeyCode } from 'vs/base/common/keyCodes';
|
||||
import { HoverWidget } from 'vs/base/browser/ui/hover/hoverWidget';
|
||||
import { MarkerHover, MarkerHoverParticipant } from 'vs/editor/contrib/hover/markerHoverParticipant';
|
||||
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
|
||||
import { MarkdownHover, MarkdownHoverParticipant } from 'vs/editor/contrib/hover/markdownHoverParticipant';
|
||||
|
||||
const $ = dom.$;
|
||||
export interface IHoverPart {
|
||||
readonly range: Range;
|
||||
equals(other: IHoverPart): boolean;
|
||||
}
|
||||
|
||||
class ColorHover {
|
||||
export interface IEditorHover {
|
||||
hide(): void;
|
||||
onContentsChanged(): void;
|
||||
}
|
||||
|
||||
export interface IEditorHoverParticipant<T extends IHoverPart = IHoverPart> {
|
||||
computeSync(hoverRange: Range, lineDecorations: IModelDecoration[]): T[];
|
||||
computeAsync?(range: Range, token: CancellationToken): Promise<T[]>;
|
||||
renderHoverParts(hoverParts: T[], fragment: DocumentFragment): IDisposable;
|
||||
}
|
||||
|
||||
class ColorHover implements IHoverPart {
|
||||
|
||||
constructor(
|
||||
public readonly range: IRange,
|
||||
public readonly range: Range,
|
||||
public readonly color: IColor,
|
||||
public readonly provider: DocumentColorProvider
|
||||
) { }
|
||||
|
||||
equals(other: IHoverPart): boolean {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
class MarkerHover {
|
||||
|
||||
class HoverPartInfo {
|
||||
constructor(
|
||||
public readonly range: IRange,
|
||||
public readonly marker: IMarker,
|
||||
public readonly owner: IEditorHoverParticipant | null,
|
||||
public readonly data: IHoverPart
|
||||
) { }
|
||||
}
|
||||
|
||||
type HoverPart = MarkdownHover | ColorHover | MarkerHover;
|
||||
|
||||
class ModesContentComputer implements IHoverComputer<HoverPart[]> {
|
||||
class ModesContentComputer implements IHoverComputer<HoverPartInfo[]> {
|
||||
|
||||
private readonly _editor: ICodeEditor;
|
||||
private _result: HoverPart[];
|
||||
private _range?: Range;
|
||||
private _result: HoverPartInfo[];
|
||||
private _range: Range | null;
|
||||
|
||||
constructor(
|
||||
editor: ICodeEditor,
|
||||
private readonly _markerDecorationsService: IMarkerDecorationsService
|
||||
private readonly _markerHoverParticipant: IEditorHoverParticipant<MarkerHover>,
|
||||
private readonly _markdownHoverParticipant: MarkdownHoverParticipant
|
||||
) {
|
||||
this._editor = editor;
|
||||
this._result = [];
|
||||
this._range = null;
|
||||
}
|
||||
|
||||
setRange(range: Range): void {
|
||||
public setRange(range: Range): void {
|
||||
this._range = range;
|
||||
this._result = [];
|
||||
}
|
||||
|
||||
clearResult(): void {
|
||||
public clearResult(): void {
|
||||
this._result = [];
|
||||
}
|
||||
|
||||
computeAsync(token: CancellationToken): Promise<HoverPart[]> {
|
||||
public async computeAsync(token: CancellationToken): Promise<HoverPartInfo[]> {
|
||||
if (!this._editor.hasModel() || !this._range) {
|
||||
return Promise.resolve([]);
|
||||
}
|
||||
|
||||
const model = this._editor.getModel();
|
||||
|
||||
if (!HoverProviderRegistry.has(model)) {
|
||||
return Promise.resolve([]);
|
||||
}
|
||||
|
||||
return getHover(model, new Position(
|
||||
this._range.startLineNumber,
|
||||
this._range.startColumn
|
||||
), token);
|
||||
const markdownHovers = await this._markdownHoverParticipant.computeAsync(this._range, token);
|
||||
return markdownHovers.map(h => new HoverPartInfo(this._markdownHoverParticipant, h));
|
||||
}
|
||||
|
||||
computeSync(): HoverPart[] {
|
||||
public computeSync(): HoverPartInfo[] {
|
||||
if (!this._editor.hasModel() || !this._range) {
|
||||
return [];
|
||||
}
|
||||
|
||||
const model = this._editor.getModel();
|
||||
const lineNumber = this._range.startLineNumber;
|
||||
const hoverRange = this._range;
|
||||
const lineNumber = hoverRange.startLineNumber;
|
||||
|
||||
if (lineNumber > this._editor.getModel().getLineCount()) {
|
||||
// Illegal line number => no results
|
||||
return [];
|
||||
}
|
||||
|
||||
const colorDetector = ColorDetector.get(this._editor);
|
||||
const maxColumn = model.getLineMaxColumn(lineNumber);
|
||||
const lineDecorations = this._editor.getLineDecorations(lineNumber);
|
||||
let didFindColor = false;
|
||||
|
||||
const hoverRange = this._range;
|
||||
const result = lineDecorations.map((d): HoverPart | null => {
|
||||
const lineDecorations = this._editor.getLineDecorations(lineNumber).filter((d) => {
|
||||
const startColumn = (d.range.startLineNumber === lineNumber) ? d.range.startColumn : 1;
|
||||
const endColumn = (d.range.endLineNumber === lineNumber) ? d.range.endColumn : maxColumn;
|
||||
|
||||
if (startColumn > hoverRange.startColumn || hoverRange.endColumn > endColumn) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const range = new Range(hoverRange.startLineNumber, startColumn, hoverRange.startLineNumber, endColumn);
|
||||
const marker = this._markerDecorationsService.getMarker(model, d);
|
||||
if (marker) {
|
||||
return new MarkerHover(range, marker);
|
||||
}
|
||||
|
||||
const colorData = colorDetector.getColorData(d.range.getStartPosition());
|
||||
|
||||
if (!didFindColor && colorData) {
|
||||
didFindColor = true;
|
||||
|
||||
const { color, range } = colorData.colorInfo;
|
||||
return new ColorHover(range, color, colorData.provider);
|
||||
} else {
|
||||
if (isEmptyMarkdownString(d.options.hoverMessage)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const contents: IMarkdownString[] = d.options.hoverMessage ? asArray(d.options.hoverMessage) : [];
|
||||
return { contents, range };
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
});
|
||||
|
||||
let result: HoverPartInfo[] = [];
|
||||
|
||||
const colorDetector = ColorDetector.get(this._editor);
|
||||
for (const d of lineDecorations) {
|
||||
const colorData = colorDetector.getColorData(d.range.getStartPosition());
|
||||
if (colorData) {
|
||||
const { color, range } = colorData.colorInfo;
|
||||
result.push(new HoverPartInfo(null, new ColorHover(Range.lift(range), color, colorData.provider)));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
const markdownHovers = this._markdownHoverParticipant.computeSync(this._range, lineDecorations);
|
||||
result = result.concat(markdownHovers.map(h => new HoverPartInfo(this._markdownHoverParticipant, h)));
|
||||
|
||||
const markerHovers = this._markerHoverParticipant.computeSync(this._range, lineDecorations);
|
||||
result = result.concat(markerHovers.map(h => new HoverPartInfo(this._markerHoverParticipant, h)));
|
||||
|
||||
return coalesce(result);
|
||||
}
|
||||
|
||||
onResult(result: HoverPart[], isFromSynchronousComputation: boolean): void {
|
||||
public onResult(result: HoverPartInfo[], isFromSynchronousComputation: boolean): void {
|
||||
// Always put synchronous messages before asynchronous ones
|
||||
if (isFromSynchronousComputation) {
|
||||
this._result = result.concat(this._result.sort((a, b) => {
|
||||
if (a instanceof ColorHover) { // sort picker messages at to the top
|
||||
return -1;
|
||||
} else if (b instanceof ColorHover) {
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}));
|
||||
this._result = result.concat(this._result);
|
||||
} else {
|
||||
this._result = this._result.concat(result);
|
||||
}
|
||||
}
|
||||
|
||||
getResult(): HoverPart[] {
|
||||
public getResult(): HoverPartInfo[] {
|
||||
return this._result.slice(0);
|
||||
}
|
||||
|
||||
getResultWithLoadingMessage(): HoverPart[] {
|
||||
return this._result.slice(0).concat([this._getLoadingMessage()]);
|
||||
}
|
||||
public getResultWithLoadingMessage(): HoverPartInfo[] {
|
||||
if (this._range) {
|
||||
const loadingMessage = new HoverPartInfo(this._markdownHoverParticipant, this._markdownHoverParticipant.createLoadingMessage(this._range));
|
||||
return this._result.slice(0).concat([loadingMessage]);
|
||||
|
||||
private _getLoadingMessage(): HoverPart {
|
||||
return {
|
||||
range: this._range,
|
||||
contents: [new MarkdownString().appendText(nls.localize('modesContentHover.loading', "Loading..."))]
|
||||
};
|
||||
}
|
||||
return this._result.slice(0);
|
||||
}
|
||||
}
|
||||
|
||||
const markerCodeActionTrigger: CodeActionTrigger = {
|
||||
type: CodeActionTriggerType.Manual,
|
||||
filter: { include: CodeActionKind.QuickFix }
|
||||
};
|
||||
|
||||
export class ModesContentHoverWidget extends ContentHoverWidget {
|
||||
export class ModesContentHoverWidget extends Widget implements IContentWidget, IEditorHover {
|
||||
|
||||
static readonly ID = 'editor.contrib.modesContentHoverWidget';
|
||||
|
||||
private _messages: HoverPart[];
|
||||
private readonly _markerHoverParticipant: IEditorHoverParticipant<MarkerHover>;
|
||||
private readonly _markdownHoverParticipant: MarkdownHoverParticipant;
|
||||
|
||||
private readonly _hover: HoverWidget;
|
||||
private readonly _id: string;
|
||||
private readonly _editor: ICodeEditor;
|
||||
private _isVisible: boolean;
|
||||
private _showAtPosition: Position | null;
|
||||
private _showAtRange: Range | null;
|
||||
private _stoleFocus: boolean;
|
||||
|
||||
// IContentWidget.allowEditorOverflow
|
||||
public readonly allowEditorOverflow = true;
|
||||
|
||||
private _messages: HoverPartInfo[];
|
||||
private _lastRange: Range | null;
|
||||
private readonly _computer: ModesContentComputer;
|
||||
private readonly _hoverOperation: HoverOperation<HoverPart[]>;
|
||||
private readonly _hoverOperation: HoverOperation<HoverPartInfo[]>;
|
||||
private _highlightDecorations: string[];
|
||||
private _isChangingDecorations: boolean;
|
||||
private _shouldFocus: boolean;
|
||||
private _colorPicker: ColorPickerWidget | null;
|
||||
|
||||
private _codeLink?: HTMLElement;
|
||||
|
||||
private readonly renderDisposable = this._register(new MutableDisposable<IDisposable>());
|
||||
private _renderDisposable: IDisposable | null;
|
||||
|
||||
constructor(
|
||||
editor: ICodeEditor,
|
||||
_hoverVisibleKey: IContextKey<boolean>,
|
||||
markerDecorationsService: IMarkerDecorationsService,
|
||||
keybindingService: IKeybindingService,
|
||||
private readonly _hoverVisibleKey: IContextKey<boolean>,
|
||||
instantiationService: IInstantiationService,
|
||||
private readonly _themeService: IThemeService,
|
||||
private readonly _modeService: IModeService,
|
||||
private readonly _openerService: IOpenerService = NullOpenerService,
|
||||
) {
|
||||
super(ModesContentHoverWidget.ID, editor, _hoverVisibleKey, keybindingService);
|
||||
super();
|
||||
|
||||
this._markerHoverParticipant = instantiationService.createInstance(MarkerHoverParticipant, editor, this);
|
||||
this._markdownHoverParticipant = instantiationService.createInstance(MarkdownHoverParticipant, editor, this);
|
||||
|
||||
this._hover = this._register(new HoverWidget());
|
||||
this._id = ModesContentHoverWidget.ID;
|
||||
this._editor = editor;
|
||||
this._isVisible = false;
|
||||
this._stoleFocus = false;
|
||||
this._renderDisposable = null;
|
||||
|
||||
this.onkeydown(this._hover.containerDomNode, (e: IKeyboardEvent) => {
|
||||
if (e.equals(KeyCode.Escape)) {
|
||||
this.hide();
|
||||
}
|
||||
});
|
||||
|
||||
this._register(this._editor.onDidChangeConfiguration((e: ConfigurationChangedEvent) => {
|
||||
if (e.hasChanged(EditorOption.fontInfo)) {
|
||||
this._updateFont();
|
||||
}
|
||||
}));
|
||||
|
||||
this._editor.onDidLayoutChange(() => this.layout());
|
||||
|
||||
this.layout();
|
||||
this._editor.addContentWidget(this);
|
||||
this._showAtPosition = null;
|
||||
this._showAtRange = null;
|
||||
this._stoleFocus = false;
|
||||
|
||||
this._messages = [];
|
||||
this._lastRange = null;
|
||||
this._computer = new ModesContentComputer(this._editor, markerDecorationsService);
|
||||
this._computer = new ModesContentComputer(this._editor, this._markerHoverParticipant, this._markdownHoverParticipant);
|
||||
this._highlightDecorations = [];
|
||||
this._isChangingDecorations = false;
|
||||
this._shouldFocus = false;
|
||||
@@ -246,15 +260,15 @@ export class ModesContentHoverWidget extends ContentHoverWidget {
|
||||
this._register(dom.addStandardDisposableListener(this.getDomNode(), dom.EventType.BLUR, () => {
|
||||
this.getDomNode().classList.remove('colorpicker-hover');
|
||||
}));
|
||||
this._register(editor.onDidChangeConfiguration((e) => {
|
||||
this._register(editor.onDidChangeConfiguration(() => {
|
||||
this._hoverOperation.setHoverTime(this._editor.getOption(EditorOption.hover).delay);
|
||||
}));
|
||||
this._register(TokenizationRegistry.onDidChange((e) => {
|
||||
if (this.isVisible && this._lastRange && this._messages.length > 0) {
|
||||
this._register(TokenizationRegistry.onDidChange(() => {
|
||||
if (this._isVisible && this._lastRange && this._messages.length > 0) {
|
||||
this._messages = this._messages.map(msg => {
|
||||
// If a color hover is visible, we need to update the message that
|
||||
// created it so that the color matches the last chosen color
|
||||
if (msg instanceof ColorHover && !!this._lastRange?.intersectRanges(msg.range) && this._colorPicker?.model.color) {
|
||||
if (msg.data instanceof ColorHover && !!this._lastRange?.intersectRanges(msg.data.range) && this._colorPicker?.model.color) {
|
||||
const color = this._colorPicker.model.color;
|
||||
const newColor = {
|
||||
red: color.rgba.r / 255,
|
||||
@@ -262,7 +276,7 @@ export class ModesContentHoverWidget extends ContentHoverWidget {
|
||||
blue: color.rgba.b / 255,
|
||||
alpha: color.rgba.a
|
||||
};
|
||||
return new ColorHover(msg.range, newColor, msg.provider);
|
||||
return new HoverPartInfo(msg.owner, new ColorHover(msg.data.range, newColor, msg.data.provider));
|
||||
} else {
|
||||
return msg;
|
||||
}
|
||||
@@ -274,16 +288,81 @@ export class ModesContentHoverWidget extends ContentHoverWidget {
|
||||
}));
|
||||
}
|
||||
|
||||
dispose(): void {
|
||||
public dispose(): void {
|
||||
this._hoverOperation.cancel();
|
||||
this._editor.removeContentWidget(this);
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
onModelDecorationsChanged(): void {
|
||||
public getId(): string {
|
||||
return this._id;
|
||||
}
|
||||
|
||||
public getDomNode(): HTMLElement {
|
||||
return this._hover.containerDomNode;
|
||||
}
|
||||
|
||||
public showAt(position: Position, range: Range | null, focus: boolean): void {
|
||||
// Position has changed
|
||||
this._showAtPosition = position;
|
||||
this._showAtRange = range;
|
||||
this._hoverVisibleKey.set(true);
|
||||
this._isVisible = true;
|
||||
this._hover.containerDomNode.classList.toggle('hidden', !this._isVisible);
|
||||
|
||||
this._editor.layoutContentWidget(this);
|
||||
// Simply force a synchronous render on the editor
|
||||
// such that the widget does not really render with left = '0px'
|
||||
this._editor.render();
|
||||
this._stoleFocus = focus;
|
||||
if (focus) {
|
||||
this._hover.containerDomNode.focus();
|
||||
}
|
||||
}
|
||||
|
||||
public getPosition(): IContentWidgetPosition | null {
|
||||
if (this._isVisible) {
|
||||
return {
|
||||
position: this._showAtPosition,
|
||||
range: this._showAtRange,
|
||||
preference: [
|
||||
ContentWidgetPositionPreference.ABOVE,
|
||||
ContentWidgetPositionPreference.BELOW
|
||||
]
|
||||
};
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private _updateFont(): void {
|
||||
const codeClasses: HTMLElement[] = Array.prototype.slice.call(this._hover.contentsDomNode.getElementsByClassName('code'));
|
||||
codeClasses.forEach(node => this._editor.applyFontInfo(node));
|
||||
}
|
||||
|
||||
private _updateContents(node: Node): void {
|
||||
this._hover.contentsDomNode.textContent = '';
|
||||
this._hover.contentsDomNode.appendChild(node);
|
||||
this._updateFont();
|
||||
|
||||
this._editor.layoutContentWidget(this);
|
||||
this._hover.onContentsChanged();
|
||||
}
|
||||
|
||||
private layout(): void {
|
||||
const height = Math.max(this._editor.getLayoutInfo().height / 4, 250);
|
||||
const { fontSize, lineHeight } = this._editor.getOption(EditorOption.fontInfo);
|
||||
|
||||
this._hover.contentsDomNode.style.fontSize = `${fontSize}px`;
|
||||
this._hover.contentsDomNode.style.lineHeight = `${lineHeight}px`;
|
||||
this._hover.contentsDomNode.style.maxHeight = `${height}px`;
|
||||
this._hover.contentsDomNode.style.maxWidth = `${Math.max(this._editor.getLayoutInfo().width * 0.66, 500)}px`;
|
||||
}
|
||||
|
||||
public onModelDecorationsChanged(): void {
|
||||
if (this._isChangingDecorations) {
|
||||
return;
|
||||
}
|
||||
if (this.isVisible) {
|
||||
if (this._isVisible) {
|
||||
// The decorations have changed and the hover is visible,
|
||||
// we need to recompute the displayed text
|
||||
this._hoverOperation.cancel();
|
||||
@@ -295,7 +374,7 @@ export class ModesContentHoverWidget extends ContentHoverWidget {
|
||||
}
|
||||
}
|
||||
|
||||
startShowingAt(range: Range, mode: HoverStartMode, focus: boolean): void {
|
||||
public startShowingAt(range: Range, mode: HoverStartMode, focus: boolean): void {
|
||||
if (this._lastRange && this._lastRange.equalsRange(range)) {
|
||||
// We have to show the widget at the exact same range as before, so no work is needed
|
||||
return;
|
||||
@@ -303,17 +382,17 @@ export class ModesContentHoverWidget extends ContentHoverWidget {
|
||||
|
||||
this._hoverOperation.cancel();
|
||||
|
||||
if (this.isVisible) {
|
||||
if (this._isVisible) {
|
||||
// The range might have changed, but the hover is visible
|
||||
// Instead of hiding it completely, filter out messages that are still in the new range and
|
||||
// kick off a new computation
|
||||
if (!this._showAtPosition || this._showAtPosition.lineNumber !== range.startLineNumber) {
|
||||
this.hide();
|
||||
} else {
|
||||
let filteredMessages: HoverPart[] = [];
|
||||
let filteredMessages: HoverPartInfo[] = [];
|
||||
for (let i = 0, len = this._messages.length; i < len; i++) {
|
||||
const msg = this._messages[i];
|
||||
const rng = msg.range;
|
||||
const rng = msg.data.range;
|
||||
if (rng && rng.startColumn <= range.startColumn && rng.endColumn >= range.endColumn) {
|
||||
filteredMessages.push(msg);
|
||||
}
|
||||
@@ -335,25 +414,45 @@ export class ModesContentHoverWidget extends ContentHoverWidget {
|
||||
this._hoverOperation.start(mode);
|
||||
}
|
||||
|
||||
hide(): void {
|
||||
public hide(): void {
|
||||
this._lastRange = null;
|
||||
this._hoverOperation.cancel();
|
||||
super.hide();
|
||||
|
||||
if (this._isVisible) {
|
||||
setTimeout(() => {
|
||||
// Give commands a chance to see the key
|
||||
if (!this._isVisible) {
|
||||
this._hoverVisibleKey.set(false);
|
||||
}
|
||||
}, 0);
|
||||
this._isVisible = false;
|
||||
this._hover.containerDomNode.classList.toggle('hidden', !this._isVisible);
|
||||
|
||||
this._editor.layoutContentWidget(this);
|
||||
if (this._stoleFocus) {
|
||||
this._editor.focus();
|
||||
}
|
||||
}
|
||||
|
||||
this._isChangingDecorations = true;
|
||||
this._highlightDecorations = this._editor.deltaDecorations(this._highlightDecorations, []);
|
||||
this._isChangingDecorations = false;
|
||||
this.renderDisposable.clear();
|
||||
if (this._renderDisposable) {
|
||||
this._renderDisposable.dispose();
|
||||
this._renderDisposable = null;
|
||||
}
|
||||
this._colorPicker = null;
|
||||
}
|
||||
|
||||
isColorPickerVisible(): boolean {
|
||||
if (this._colorPicker) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
public isColorPickerVisible(): boolean {
|
||||
return !!this._colorPicker;
|
||||
}
|
||||
|
||||
private _withResult(result: HoverPart[], complete: boolean): void {
|
||||
public onContentsChanged(): void {
|
||||
this._hover.onContentsChanged();
|
||||
}
|
||||
|
||||
private _withResult(result: HoverPartInfo[], complete: boolean): void {
|
||||
this._messages = result;
|
||||
|
||||
if (this._lastRange && this._messages.length > 0) {
|
||||
@@ -363,20 +462,24 @@ export class ModesContentHoverWidget extends ContentHoverWidget {
|
||||
}
|
||||
}
|
||||
|
||||
private _renderMessages(renderRange: Range, messages: HoverPart[]): void {
|
||||
this.renderDisposable.dispose();
|
||||
private _renderMessages(renderRange: Range, messages: HoverPartInfo[]): void {
|
||||
if (this._renderDisposable) {
|
||||
this._renderDisposable.dispose();
|
||||
this._renderDisposable = null;
|
||||
}
|
||||
this._colorPicker = null;
|
||||
|
||||
// update column from which to show
|
||||
let renderColumn = Constants.MAX_SAFE_SMALL_INTEGER;
|
||||
let highlightRange: Range | null = messages[0].range ? Range.lift(messages[0].range) : null;
|
||||
let highlightRange: Range | null = messages[0].data.range ? Range.lift(messages[0].data.range) : null;
|
||||
let fragment = document.createDocumentFragment();
|
||||
let isEmptyHoverContent = true;
|
||||
|
||||
let containColorPicker = false;
|
||||
const markdownDisposeables = new DisposableStore();
|
||||
const disposables = new DisposableStore();
|
||||
const markerMessages: MarkerHover[] = [];
|
||||
messages.forEach((msg) => {
|
||||
const markdownParts: MarkdownHover[] = [];
|
||||
messages.forEach((_msg) => {
|
||||
const msg = _msg.data;
|
||||
if (!msg.range) {
|
||||
return;
|
||||
}
|
||||
@@ -464,46 +567,37 @@ export class ModesContentHoverWidget extends ContentHoverWidget {
|
||||
|
||||
this._colorPicker = widget;
|
||||
this.showAt(range.getStartPosition(), range, this._shouldFocus);
|
||||
this.updateContents(fragment);
|
||||
this._updateContents(fragment);
|
||||
this._colorPicker.layout();
|
||||
|
||||
this.renderDisposable.value = combinedDisposable(colorListener, colorChangeListener, widget, markdownDisposeables);
|
||||
this._renderDisposable = combinedDisposable(colorListener, colorChangeListener, widget, disposables);
|
||||
});
|
||||
} else {
|
||||
if (msg instanceof MarkerHover) {
|
||||
markerMessages.push(msg);
|
||||
isEmptyHoverContent = false;
|
||||
} else {
|
||||
msg.contents
|
||||
.filter(contents => !isEmptyMarkdownString(contents))
|
||||
.forEach(contents => {
|
||||
const markdownHoverElement = $('div.hover-row.markdown-hover');
|
||||
const hoverContentsElement = dom.append(markdownHoverElement, $('div.hover-contents'));
|
||||
const renderer = markdownDisposeables.add(new MarkdownRenderer({ editor: this._editor }, this._modeService, this._openerService));
|
||||
markdownDisposeables.add(renderer.onDidRenderAsync(() => {
|
||||
hoverContentsElement.className = 'hover-contents code-hover-contents';
|
||||
this._hover.onContentsChanged();
|
||||
}));
|
||||
const renderedContents = markdownDisposeables.add(renderer.render(contents));
|
||||
hoverContentsElement.appendChild(renderedContents.element);
|
||||
fragment.appendChild(markdownHoverElement);
|
||||
isEmptyHoverContent = false;
|
||||
});
|
||||
if (msg instanceof MarkdownHover) {
|
||||
markdownParts.push(msg);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
if (markerMessages.length) {
|
||||
markerMessages.forEach(msg => fragment.appendChild(this.renderMarkerHover(msg)));
|
||||
const markerHoverForStatusbar = markerMessages.length === 1 ? markerMessages[0] : markerMessages.sort((a, b) => MarkerSeverity.compare(a.marker.severity, b.marker.severity))[0];
|
||||
fragment.appendChild(this.renderMarkerStatusbar(markerHoverForStatusbar));
|
||||
if (markdownParts.length > 0) {
|
||||
disposables.add(this._markdownHoverParticipant.renderHoverParts(markdownParts, fragment));
|
||||
}
|
||||
|
||||
if (markerMessages.length) {
|
||||
disposables.add(this._markerHoverParticipant.renderHoverParts(markerMessages, fragment));
|
||||
}
|
||||
|
||||
this._renderDisposable = disposables;
|
||||
|
||||
// show
|
||||
|
||||
if (!containColorPicker && !isEmptyHoverContent) {
|
||||
if (!containColorPicker && fragment.hasChildNodes()) {
|
||||
this.showAt(new Position(renderRange.startLineNumber, renderColumn), highlightRange, this._shouldFocus);
|
||||
this.updateContents(fragment);
|
||||
this._updateContents(fragment);
|
||||
}
|
||||
|
||||
this._isChangingDecorations = true;
|
||||
@@ -514,175 +608,17 @@ export class ModesContentHoverWidget extends ContentHoverWidget {
|
||||
this._isChangingDecorations = false;
|
||||
}
|
||||
|
||||
private renderMarkerHover(markerHover: MarkerHover): HTMLElement {
|
||||
const hoverElement = $('div.hover-row');
|
||||
const markerElement = dom.append(hoverElement, $('div.marker.hover-contents'));
|
||||
const { source, message, code, relatedInformation } = markerHover.marker;
|
||||
|
||||
this._editor.applyFontInfo(markerElement);
|
||||
const messageElement = dom.append(markerElement, $('span'));
|
||||
messageElement.style.whiteSpace = 'pre-wrap';
|
||||
messageElement.innerText = message;
|
||||
|
||||
if (source || code) {
|
||||
// Code has link
|
||||
if (code && typeof code !== 'string') {
|
||||
const sourceAndCodeElement = $('span');
|
||||
if (source) {
|
||||
const sourceElement = dom.append(sourceAndCodeElement, $('span'));
|
||||
sourceElement.innerText = source;
|
||||
}
|
||||
this._codeLink = dom.append(sourceAndCodeElement, $('a.code-link'));
|
||||
this._codeLink.setAttribute('href', code.target.toString());
|
||||
|
||||
this._codeLink.onclick = (e) => {
|
||||
this._openerService.open(code.target);
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
};
|
||||
|
||||
const codeElement = dom.append(this._codeLink, $('span'));
|
||||
codeElement.innerText = code.value;
|
||||
|
||||
const detailsElement = dom.append(markerElement, sourceAndCodeElement);
|
||||
detailsElement.style.opacity = '0.6';
|
||||
detailsElement.style.paddingLeft = '6px';
|
||||
} else {
|
||||
const detailsElement = dom.append(markerElement, $('span'));
|
||||
detailsElement.style.opacity = '0.6';
|
||||
detailsElement.style.paddingLeft = '6px';
|
||||
detailsElement.innerText = source && code ? `${source}(${code})` : source ? source : `(${code})`;
|
||||
}
|
||||
}
|
||||
|
||||
if (isNonEmptyArray(relatedInformation)) {
|
||||
for (const { message, resource, startLineNumber, startColumn } of relatedInformation) {
|
||||
const relatedInfoContainer = dom.append(markerElement, $('div'));
|
||||
relatedInfoContainer.style.marginTop = '8px';
|
||||
const a = dom.append(relatedInfoContainer, $('a'));
|
||||
a.innerText = `${basename(resource)}(${startLineNumber}, ${startColumn}): `;
|
||||
a.style.cursor = 'pointer';
|
||||
a.onclick = e => {
|
||||
e.stopPropagation();
|
||||
e.preventDefault();
|
||||
if (this._openerService) {
|
||||
this._openerService.open(resource.with({ fragment: `${startLineNumber},${startColumn}` }), { fromUserGesture: true }).catch(onUnexpectedError);
|
||||
}
|
||||
};
|
||||
const messageElement = dom.append<HTMLAnchorElement>(relatedInfoContainer, $('span'));
|
||||
messageElement.innerText = message;
|
||||
this._editor.applyFontInfo(messageElement);
|
||||
}
|
||||
}
|
||||
|
||||
return hoverElement;
|
||||
}
|
||||
|
||||
private recentMarkerCodeActionsInfo: { marker: IMarker, hasCodeActions: boolean } | undefined = undefined;
|
||||
private renderMarkerStatusbar(markerHover: MarkerHover): HTMLElement {
|
||||
const hoverElement = $('div.hover-row.status-bar');
|
||||
const disposables = new DisposableStore();
|
||||
const actionsElement = dom.append(hoverElement, $('div.actions'));
|
||||
if (markerHover.marker.severity === MarkerSeverity.Error || markerHover.marker.severity === MarkerSeverity.Warning || markerHover.marker.severity === MarkerSeverity.Info) {
|
||||
disposables.add(this._renderAction(actionsElement, {
|
||||
label: nls.localize('peek problem', "Peek Problem"),
|
||||
commandId: NextMarkerAction.ID,
|
||||
run: () => {
|
||||
this.hide();
|
||||
MarkerController.get(this._editor).showAtMarker(markerHover.marker);
|
||||
this._editor.focus();
|
||||
}
|
||||
}));
|
||||
}
|
||||
|
||||
if (!this._editor.getOption(EditorOption.readOnly)) {
|
||||
const quickfixPlaceholderElement = dom.append(actionsElement, $('div'));
|
||||
if (this.recentMarkerCodeActionsInfo) {
|
||||
if (IMarkerData.makeKey(this.recentMarkerCodeActionsInfo.marker) === IMarkerData.makeKey(markerHover.marker)) {
|
||||
if (!this.recentMarkerCodeActionsInfo.hasCodeActions) {
|
||||
quickfixPlaceholderElement.textContent = nls.localize('noQuickFixes', "No quick fixes available");
|
||||
}
|
||||
} else {
|
||||
this.recentMarkerCodeActionsInfo = undefined;
|
||||
}
|
||||
}
|
||||
const updatePlaceholderDisposable = disposables.add(disposableTimeout(() => quickfixPlaceholderElement.textContent = nls.localize('checkingForQuickFixes', "Checking for quick fixes..."), 64));
|
||||
const codeActionsPromise = this.getCodeActions(markerHover.marker);
|
||||
disposables.add(toDisposable(() => codeActionsPromise.cancel()));
|
||||
codeActionsPromise.then(actions => {
|
||||
updatePlaceholderDisposable.dispose();
|
||||
this.recentMarkerCodeActionsInfo = { marker: markerHover.marker, hasCodeActions: actions.validActions.length > 0 };
|
||||
|
||||
if (!this.recentMarkerCodeActionsInfo.hasCodeActions) {
|
||||
actions.dispose();
|
||||
quickfixPlaceholderElement.textContent = nls.localize('noQuickFixes', "No quick fixes available");
|
||||
return;
|
||||
}
|
||||
quickfixPlaceholderElement.style.display = 'none';
|
||||
|
||||
let showing = false;
|
||||
disposables.add(toDisposable(() => {
|
||||
if (!showing) {
|
||||
actions.dispose();
|
||||
}
|
||||
}));
|
||||
|
||||
disposables.add(this._renderAction(actionsElement, {
|
||||
label: nls.localize('quick fixes', "Quick Fix..."),
|
||||
commandId: QuickFixAction.Id,
|
||||
run: (target) => {
|
||||
showing = true;
|
||||
const controller = QuickFixController.get(this._editor);
|
||||
const elementPosition = dom.getDomNodePagePosition(target);
|
||||
// Hide the hover pre-emptively, otherwise the editor can close the code actions
|
||||
// context menu as well when using keyboard navigation
|
||||
this.hide();
|
||||
controller.showCodeActions(markerCodeActionTrigger, actions, {
|
||||
x: elementPosition.left + 6,
|
||||
y: elementPosition.top + elementPosition.height + 6
|
||||
});
|
||||
}
|
||||
}));
|
||||
});
|
||||
}
|
||||
|
||||
this.renderDisposable.value = disposables;
|
||||
return hoverElement;
|
||||
}
|
||||
|
||||
private getCodeActions(marker: IMarker): CancelablePromise<CodeActionSet> {
|
||||
return createCancelablePromise(cancellationToken => {
|
||||
return getCodeActions(
|
||||
this._editor.getModel()!,
|
||||
new Range(marker.startLineNumber, marker.startColumn, marker.endLineNumber, marker.endColumn),
|
||||
markerCodeActionTrigger,
|
||||
Progress.None,
|
||||
cancellationToken);
|
||||
});
|
||||
}
|
||||
|
||||
private static readonly _DECORATION_OPTIONS = ModelDecorationOptions.register({
|
||||
className: 'hoverHighlight'
|
||||
});
|
||||
}
|
||||
|
||||
function hoverContentsEquals(first: HoverPart[], second: HoverPart[]): boolean {
|
||||
if ((!first && second) || (first && !second) || first.length !== second.length) {
|
||||
function hoverContentsEquals(first: HoverPartInfo[], second: HoverPartInfo[]): boolean {
|
||||
if (first.length !== second.length) {
|
||||
return false;
|
||||
}
|
||||
for (let i = 0; i < first.length; i++) {
|
||||
const firstElement = first[i];
|
||||
const secondElement = second[i];
|
||||
if (firstElement instanceof MarkerHover && secondElement instanceof MarkerHover) {
|
||||
return IMarkerData.makeKey(firstElement.marker) === IMarkerData.makeKey(secondElement.marker);
|
||||
}
|
||||
if (firstElement instanceof ColorHover || secondElement instanceof ColorHover) {
|
||||
return false;
|
||||
}
|
||||
if (firstElement instanceof MarkerHover || secondElement instanceof MarkerHover) {
|
||||
return false;
|
||||
}
|
||||
if (!markedStringsEquals(firstElement.contents, secondElement.contents)) {
|
||||
if (!first[i].data.equals(second[i].data)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,227 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { RunOnceScheduler } from 'vs/base/common/async';
|
||||
import { onUnexpectedExternalError } from 'vs/base/common/errors';
|
||||
import { hash } from 'vs/base/common/hash';
|
||||
import { DisposableStore, toDisposable } from 'vs/base/common/lifecycle';
|
||||
import { ICodeEditor } from 'vs/editor/browser/editorBrowser';
|
||||
import { registerEditorContribution } from 'vs/editor/browser/editorExtensions';
|
||||
import { ICodeEditorService } from 'vs/editor/browser/services/codeEditorService';
|
||||
import { IContentDecorationRenderOptions, IEditorContribution } from 'vs/editor/common/editorCommon';
|
||||
import { IModelDeltaDecoration, ITextModel } from 'vs/editor/common/model';
|
||||
import { InlineHintsProvider, InlineHintsProviderRegistry, InlineHint } from 'vs/editor/common/modes';
|
||||
import { EditorOption } from 'vs/editor/common/config/editorOptions';
|
||||
import { flatten } from 'vs/base/common/arrays';
|
||||
import { editorInlineHintForeground, editorInlineHintBackground } from 'vs/platform/theme/common/colorRegistry';
|
||||
import { CancellationToken, CancellationTokenSource } from 'vs/base/common/cancellation';
|
||||
import { IThemeService } from 'vs/platform/theme/common/themeService';
|
||||
import { Range } from 'vs/editor/common/core/range';
|
||||
import { LanguageFeatureRequestDelays } from 'vs/editor/common/modes/languageFeatureRegistry';
|
||||
import { MarkdownString } from 'vs/base/common/htmlContent';
|
||||
import { CommandsRegistry } from 'vs/platform/commands/common/commands';
|
||||
import { URI } from 'vs/base/common/uri';
|
||||
import { IRange } from 'vs/base/common/range';
|
||||
import { assertType } from 'vs/base/common/types';
|
||||
import { ITextModelService } from 'vs/editor/common/services/resolverService';
|
||||
|
||||
const MAX_DECORATORS = 500;
|
||||
|
||||
export interface InlineHintsData {
|
||||
list: InlineHint[];
|
||||
provider: InlineHintsProvider;
|
||||
}
|
||||
|
||||
export async function getInlineHints(model: ITextModel, ranges: Range[], token: CancellationToken): Promise<InlineHintsData[]> {
|
||||
const datas: InlineHintsData[] = [];
|
||||
const providers = InlineHintsProviderRegistry.ordered(model).reverse();
|
||||
const promises = flatten(providers.map(provider => ranges.map(range => Promise.resolve(provider.provideInlineHints(model, range, token)).then(result => {
|
||||
if (result) {
|
||||
datas.push({ list: result, provider });
|
||||
}
|
||||
}, err => {
|
||||
onUnexpectedExternalError(err);
|
||||
}))));
|
||||
|
||||
await Promise.all(promises);
|
||||
|
||||
return datas;
|
||||
}
|
||||
|
||||
export class InlineHintsController implements IEditorContribution {
|
||||
|
||||
static readonly ID: string = 'editor.contrib.InlineHints';
|
||||
|
||||
// static get(editor: ICodeEditor): InlineHintsController {
|
||||
// return editor.getContribution<InlineHintsController>(this.ID);
|
||||
// }
|
||||
|
||||
private readonly _disposables = new DisposableStore();
|
||||
private readonly _sessionDisposables = new DisposableStore();
|
||||
private readonly _getInlineHintsDelays = new LanguageFeatureRequestDelays(InlineHintsProviderRegistry, 250, 2500);
|
||||
|
||||
private _decorationsTypeIds: string[] = [];
|
||||
private _decorationIds: string[] = [];
|
||||
|
||||
constructor(
|
||||
private readonly _editor: ICodeEditor,
|
||||
@ICodeEditorService private readonly _codeEditorService: ICodeEditorService,
|
||||
@IThemeService private readonly _themeService: IThemeService,
|
||||
) {
|
||||
this._disposables.add(InlineHintsProviderRegistry.onDidChange(() => this._update()));
|
||||
this._disposables.add(_themeService.onDidColorThemeChange(() => this._update()));
|
||||
this._disposables.add(_editor.onDidChangeModel(() => this._update()));
|
||||
this._disposables.add(_editor.onDidChangeModelLanguage(() => this._update()));
|
||||
this._disposables.add(_editor.onDidChangeConfiguration(e => {
|
||||
if (e.hasChanged(EditorOption.inlineHints)) {
|
||||
this._update();
|
||||
}
|
||||
}));
|
||||
|
||||
this._update();
|
||||
}
|
||||
|
||||
dispose(): void {
|
||||
this._sessionDisposables.dispose();
|
||||
this._removeAllDecorations();
|
||||
this._disposables.dispose();
|
||||
}
|
||||
|
||||
private _update(): void {
|
||||
this._sessionDisposables.clear();
|
||||
|
||||
if (!this._editor.getOption(EditorOption.inlineHints).enabled) {
|
||||
this._removeAllDecorations();
|
||||
return;
|
||||
}
|
||||
|
||||
const model = this._editor.getModel();
|
||||
if (!model || !InlineHintsProviderRegistry.has(model)) {
|
||||
this._removeAllDecorations();
|
||||
return;
|
||||
}
|
||||
|
||||
const scheduler = new RunOnceScheduler(async () => {
|
||||
const t1 = Date.now();
|
||||
|
||||
const cts = new CancellationTokenSource();
|
||||
this._sessionDisposables.add(toDisposable(() => cts.dispose(true)));
|
||||
|
||||
const visibleRanges = this._editor.getVisibleRangesPlusViewportAboveBelow();
|
||||
const result = await getInlineHints(model, visibleRanges, cts.token);
|
||||
|
||||
// update moving average
|
||||
const newDelay = this._getInlineHintsDelays.update(model, Date.now() - t1);
|
||||
scheduler.delay = newDelay;
|
||||
|
||||
// render hints
|
||||
this._updateHintsDecorators(result);
|
||||
|
||||
}, this._getInlineHintsDelays.get(model));
|
||||
|
||||
this._sessionDisposables.add(scheduler);
|
||||
|
||||
// update inline hints when content or scroll position changes
|
||||
this._sessionDisposables.add(this._editor.onDidChangeModelContent(() => scheduler.schedule()));
|
||||
this._disposables.add(this._editor.onDidScrollChange(() => scheduler.schedule()));
|
||||
scheduler.schedule();
|
||||
|
||||
// update inline hints when any any provider fires an event
|
||||
const providerListener = new DisposableStore();
|
||||
this._sessionDisposables.add(providerListener);
|
||||
for (const provider of InlineHintsProviderRegistry.all(model)) {
|
||||
if (typeof provider.onDidChangeInlineHints === 'function') {
|
||||
providerListener.add(provider.onDidChangeInlineHints(() => scheduler.schedule()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private _updateHintsDecorators(hintsData: InlineHintsData[]): void {
|
||||
const { fontSize, fontFamily } = this._getLayoutInfo();
|
||||
const backgroundColor = this._themeService.getColorTheme().getColor(editorInlineHintBackground);
|
||||
const fontColor = this._themeService.getColorTheme().getColor(editorInlineHintForeground);
|
||||
|
||||
const newDecorationsTypeIds: string[] = [];
|
||||
const newDecorationsData: IModelDeltaDecoration[] = [];
|
||||
|
||||
for (const { list: hints } of hintsData) {
|
||||
|
||||
for (let j = 0; j < hints.length && newDecorationsData.length < MAX_DECORATORS; j++) {
|
||||
const { text, range, description: hoverMessage, whitespaceBefore, whitespaceAfter } = hints[j];
|
||||
const marginBefore = whitespaceBefore ? (fontSize / 3) | 0 : 0;
|
||||
const marginAfter = whitespaceAfter ? (fontSize / 3) | 0 : 0;
|
||||
|
||||
const before: IContentDecorationRenderOptions = {
|
||||
contentText: text,
|
||||
backgroundColor: `${backgroundColor}`,
|
||||
color: `${fontColor}`,
|
||||
margin: `0px ${marginAfter}px 0px ${marginBefore}px`,
|
||||
fontSize: `${fontSize}px`,
|
||||
fontFamily: fontFamily,
|
||||
padding: `0px ${(fontSize / 4) | 0}px`,
|
||||
borderRadius: `${(fontSize / 4) | 0}px`,
|
||||
};
|
||||
const key = 'inlineHints-' + hash(before).toString(16);
|
||||
this._codeEditorService.registerDecorationType(key, { before }, undefined, this._editor);
|
||||
|
||||
// decoration types are ref-counted which means we only need to
|
||||
// call register und remove equally often
|
||||
newDecorationsTypeIds.push(key);
|
||||
|
||||
const options = this._codeEditorService.resolveDecorationOptions(key, true);
|
||||
if (typeof hoverMessage === 'string') {
|
||||
options.hoverMessage = new MarkdownString().appendText(hoverMessage);
|
||||
} else if (hoverMessage) {
|
||||
options.hoverMessage = hoverMessage;
|
||||
}
|
||||
|
||||
newDecorationsData.push({
|
||||
range,
|
||||
options
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
this._decorationsTypeIds.forEach(this._codeEditorService.removeDecorationType, this._codeEditorService);
|
||||
this._decorationsTypeIds = newDecorationsTypeIds;
|
||||
|
||||
this._decorationIds = this._editor.deltaDecorations(this._decorationIds, newDecorationsData);
|
||||
}
|
||||
|
||||
private _getLayoutInfo() {
|
||||
const options = this._editor.getOption(EditorOption.inlineHints);
|
||||
const editorFontSize = this._editor.getOption(EditorOption.fontSize);
|
||||
let fontSize = options.fontSize;
|
||||
if (!fontSize || fontSize < 5 || fontSize > editorFontSize) {
|
||||
fontSize = (editorFontSize * .9) | 0;
|
||||
}
|
||||
const fontFamily = options.fontFamily;
|
||||
return { fontSize, fontFamily };
|
||||
}
|
||||
|
||||
private _removeAllDecorations(): void {
|
||||
this._decorationIds = this._editor.deltaDecorations(this._decorationIds, []);
|
||||
this._decorationsTypeIds.forEach(this._codeEditorService.removeDecorationType, this._codeEditorService);
|
||||
this._decorationsTypeIds = [];
|
||||
}
|
||||
}
|
||||
|
||||
registerEditorContribution(InlineHintsController.ID, InlineHintsController);
|
||||
|
||||
CommandsRegistry.registerCommand('_executeInlineHintProvider', async (accessor, ...args: [URI, IRange]): Promise<InlineHint[]> => {
|
||||
|
||||
const [uri, range] = args;
|
||||
assertType(URI.isUri(uri));
|
||||
assertType(Range.isIRange(range));
|
||||
|
||||
const ref = await accessor.get(ITextModelService).createModelReference(uri);
|
||||
try {
|
||||
const data = await getInlineHints(ref.object.textEditorModel, [Range.lift(range)], CancellationToken.None);
|
||||
return flatten(data.map(item => item.list)).sort((a, b) => Range.compareRangesUsingStarts(a.range, b.range));
|
||||
|
||||
} finally {
|
||||
ref.dispose();
|
||||
}
|
||||
});
|
||||
@@ -939,43 +939,39 @@ export class TransposeAction extends EditorAction {
|
||||
|
||||
export abstract class AbstractCaseAction extends EditorAction {
|
||||
public run(_accessor: ServicesAccessor, editor: ICodeEditor): void {
|
||||
let selections = editor.getSelections();
|
||||
const selections = editor.getSelections();
|
||||
if (selections === null) {
|
||||
return;
|
||||
}
|
||||
|
||||
let model = editor.getModel();
|
||||
const model = editor.getModel();
|
||||
if (model === null) {
|
||||
return;
|
||||
}
|
||||
|
||||
let wordSeparators = editor.getOption(EditorOption.wordSeparators);
|
||||
const wordSeparators = editor.getOption(EditorOption.wordSeparators);
|
||||
const textEdits: IIdentifiedSingleEditOperation[] = [];
|
||||
|
||||
let commands: ICommand[] = [];
|
||||
|
||||
for (let i = 0, len = selections.length; i < len; i++) {
|
||||
let selection = selections[i];
|
||||
for (const selection of selections) {
|
||||
if (selection.isEmpty()) {
|
||||
let cursor = selection.getStartPosition();
|
||||
const cursor = selection.getStartPosition();
|
||||
const word = editor.getConfiguredWordAtPosition(cursor);
|
||||
|
||||
if (!word) {
|
||||
continue;
|
||||
}
|
||||
|
||||
let wordRange = new Range(cursor.lineNumber, word.startColumn, cursor.lineNumber, word.endColumn);
|
||||
let text = model.getValueInRange(wordRange);
|
||||
commands.push(new ReplaceCommandThatPreservesSelection(wordRange, this._modifyText(text, wordSeparators),
|
||||
new Selection(cursor.lineNumber, cursor.column, cursor.lineNumber, cursor.column)));
|
||||
|
||||
const wordRange = new Range(cursor.lineNumber, word.startColumn, cursor.lineNumber, word.endColumn);
|
||||
const text = model.getValueInRange(wordRange);
|
||||
textEdits.push(EditOperation.replace(wordRange, this._modifyText(text, wordSeparators)));
|
||||
} else {
|
||||
let text = model.getValueInRange(selection);
|
||||
commands.push(new ReplaceCommandThatPreservesSelection(selection, this._modifyText(text, wordSeparators), selection));
|
||||
const text = model.getValueInRange(selection);
|
||||
textEdits.push(EditOperation.replace(selection, this._modifyText(text, wordSeparators)));
|
||||
}
|
||||
}
|
||||
|
||||
editor.pushUndoStop();
|
||||
editor.executeCommands(this.id, commands);
|
||||
editor.executeEdits(this.id, textEdits);
|
||||
editor.pushUndoStop();
|
||||
}
|
||||
|
||||
@@ -1049,6 +1045,25 @@ export class TitleCaseAction extends AbstractCaseAction {
|
||||
}
|
||||
}
|
||||
|
||||
export class SnakeCaseAction extends AbstractCaseAction {
|
||||
constructor() {
|
||||
super({
|
||||
id: 'editor.action.transformToSnakecase',
|
||||
label: nls.localize('editor.transformToSnakecase', "Transform to Snake Case"),
|
||||
alias: 'Transform to Snake Case',
|
||||
precondition: EditorContextKeys.writable
|
||||
});
|
||||
}
|
||||
|
||||
protected _modifyText(text: string, wordSeparators: string): string {
|
||||
return (text
|
||||
.replace(/(\p{Ll})(\p{Lu})/gmu, '$1_$2')
|
||||
.replace(/([^\b_])(\p{Lu})(\p{Ll})/gmu, '$1_$2$3')
|
||||
.toLocaleLowerCase()
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
registerEditorAction(CopyLinesUpAction);
|
||||
registerEditorAction(CopyLinesDownAction);
|
||||
registerEditorAction(DuplicateSelectionAction);
|
||||
@@ -1069,3 +1084,4 @@ registerEditorAction(TransposeAction);
|
||||
registerEditorAction(UpperCaseAction);
|
||||
registerEditorAction(LowerCaseAction);
|
||||
registerEditorAction(TitleCaseAction);
|
||||
registerEditorAction(SnakeCaseAction);
|
||||
|
||||
@@ -299,13 +299,13 @@ export class MoveLinesCommand implements ICommand {
|
||||
}
|
||||
}
|
||||
|
||||
private matchEnterRule(model: ITextModel, indentConverter: IIndentConverter, tabSize: number, line: number, oneLineAbove: number, oneLineAboveText?: string) {
|
||||
private matchEnterRule(model: ITextModel, indentConverter: IIndentConverter, tabSize: number, line: number, oneLineAbove: number, previousLineText?: string) {
|
||||
let validPrecedingLine = oneLineAbove;
|
||||
while (validPrecedingLine >= 1) {
|
||||
// ship empty lines as empty lines just inherit indentation
|
||||
let lineContent;
|
||||
if (validPrecedingLine === oneLineAbove && oneLineAboveText !== undefined) {
|
||||
lineContent = oneLineAboveText;
|
||||
if (validPrecedingLine === oneLineAbove && previousLineText !== undefined) {
|
||||
lineContent = previousLineText;
|
||||
} else {
|
||||
lineContent = model.getLineContent(validPrecedingLine);
|
||||
}
|
||||
|
||||
@@ -207,8 +207,8 @@ suite('Editor Contrib - Duplicate Selection', () => {
|
||||
withTestCodeEditor(lines.join('\n'), {}, (editor) => {
|
||||
editor.setSelections(selections);
|
||||
duplicateSelectionAction.run(null!, editor, {});
|
||||
assert.deepEqual(editor.getValue(), expectedLines.join('\n'));
|
||||
assert.deepEqual(editor.getSelections()!.map(s => s.toString()), expectedSelections.map(s => s.toString()));
|
||||
assert.deepStrictEqual(editor.getValue(), expectedLines.join('\n'));
|
||||
assert.deepStrictEqual(editor.getSelections()!.map(s => s.toString()), expectedSelections.map(s => s.toString()));
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -8,7 +8,7 @@ import { Position } from 'vs/editor/common/core/position';
|
||||
import { Selection } from 'vs/editor/common/core/selection';
|
||||
import { Handler } from 'vs/editor/common/editorCommon';
|
||||
import { ITextModel } from 'vs/editor/common/model';
|
||||
import { TitleCaseAction, DeleteAllLeftAction, DeleteAllRightAction, IndentLinesAction, InsertLineAfterAction, InsertLineBeforeAction, JoinLinesAction, LowerCaseAction, SortLinesAscendingAction, SortLinesDescendingAction, TransposeAction, UpperCaseAction, DeleteLinesAction } from 'vs/editor/contrib/linesOperations/linesOperations';
|
||||
import { TitleCaseAction, DeleteAllLeftAction, DeleteAllRightAction, IndentLinesAction, InsertLineAfterAction, InsertLineBeforeAction, JoinLinesAction, LowerCaseAction, SortLinesAscendingAction, SortLinesDescendingAction, TransposeAction, UpperCaseAction, DeleteLinesAction, SnakeCaseAction } from 'vs/editor/contrib/linesOperations/linesOperations';
|
||||
import { withTestCodeEditor } from 'vs/editor/test/browser/testCodeEditor';
|
||||
import { createTextModel } from 'vs/editor/test/common/editorTestUtils';
|
||||
import type { ICodeEditor } from 'vs/editor/browser/editorBrowser';
|
||||
@@ -19,7 +19,7 @@ function assertSelection(editor: ICodeEditor, expected: Selection | Selection[])
|
||||
if (!Array.isArray(expected)) {
|
||||
expected = [expected];
|
||||
}
|
||||
assert.deepEqual(editor.getSelections(), expected);
|
||||
assert.deepStrictEqual(editor.getSelections(), expected);
|
||||
}
|
||||
|
||||
function executeAction(action: EditorAction, editor: ICodeEditor): void {
|
||||
@@ -40,7 +40,7 @@ suite('Editor Contrib - Line Operations', () => {
|
||||
|
||||
editor.setSelection(new Selection(1, 1, 3, 5));
|
||||
executeAction(sortLinesAscendingAction, editor);
|
||||
assert.deepEqual(model.getLinesContent(), [
|
||||
assert.deepStrictEqual(model.getLinesContent(), [
|
||||
'alpha',
|
||||
'beta',
|
||||
'omicron'
|
||||
@@ -65,7 +65,7 @@ suite('Editor Contrib - Line Operations', () => {
|
||||
|
||||
editor.setSelections([new Selection(1, 1, 3, 5), new Selection(5, 1, 7, 5)]);
|
||||
executeAction(sortLinesAscendingAction, editor);
|
||||
assert.deepEqual(model.getLinesContent(), [
|
||||
assert.deepStrictEqual(model.getLinesContent(), [
|
||||
'alpha',
|
||||
'beta',
|
||||
'omicron',
|
||||
@@ -79,7 +79,7 @@ suite('Editor Contrib - Line Operations', () => {
|
||||
new Selection(5, 1, 7, 7)
|
||||
];
|
||||
editor.getSelections()!.forEach((actualSelection, index) => {
|
||||
assert.deepEqual(actualSelection.toString(), expectedSelections[index].toString());
|
||||
assert.deepStrictEqual(actualSelection.toString(), expectedSelections[index].toString());
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -98,7 +98,7 @@ suite('Editor Contrib - Line Operations', () => {
|
||||
|
||||
editor.setSelection(new Selection(1, 1, 3, 7));
|
||||
executeAction(sortLinesDescendingAction, editor);
|
||||
assert.deepEqual(model.getLinesContent(), [
|
||||
assert.deepStrictEqual(model.getLinesContent(), [
|
||||
'omicron',
|
||||
'beta',
|
||||
'alpha'
|
||||
@@ -123,7 +123,7 @@ suite('Editor Contrib - Line Operations', () => {
|
||||
|
||||
editor.setSelections([new Selection(1, 1, 3, 7), new Selection(5, 1, 7, 7)]);
|
||||
executeAction(sortLinesDescendingAction, editor);
|
||||
assert.deepEqual(model.getLinesContent(), [
|
||||
assert.deepStrictEqual(model.getLinesContent(), [
|
||||
'omicron',
|
||||
'beta',
|
||||
'alpha',
|
||||
@@ -137,7 +137,7 @@ suite('Editor Contrib - Line Operations', () => {
|
||||
new Selection(5, 1, 7, 5)
|
||||
];
|
||||
editor.getSelections()!.forEach((actualSelection, index) => {
|
||||
assert.deepEqual(actualSelection.toString(), expectedSelections[index].toString());
|
||||
assert.deepStrictEqual(actualSelection.toString(), expectedSelections[index].toString());
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -157,12 +157,12 @@ suite('Editor Contrib - Line Operations', () => {
|
||||
|
||||
editor.setSelection(new Selection(1, 2, 1, 2));
|
||||
executeAction(deleteAllLeftAction, editor);
|
||||
assert.equal(model.getLineContent(1), 'ne');
|
||||
assert.strictEqual(model.getLineContent(1), 'ne');
|
||||
|
||||
editor.setSelections([new Selection(2, 2, 2, 2), new Selection(3, 2, 3, 2)]);
|
||||
executeAction(deleteAllLeftAction, editor);
|
||||
assert.equal(model.getLineContent(2), 'wo');
|
||||
assert.equal(model.getLineContent(3), 'hree');
|
||||
assert.strictEqual(model.getLineContent(2), 'wo');
|
||||
assert.strictEqual(model.getLineContent(3), 'hree');
|
||||
});
|
||||
});
|
||||
|
||||
@@ -178,16 +178,16 @@ suite('Editor Contrib - Line Operations', () => {
|
||||
|
||||
editor.setSelection(new Selection(2, 1, 2, 1));
|
||||
executeAction(deleteAllLeftAction, editor);
|
||||
assert.equal(model.getLineContent(1), 'onetwo');
|
||||
assert.strictEqual(model.getLineContent(1), 'onetwo');
|
||||
|
||||
editor.setSelections([new Selection(1, 1, 1, 1), new Selection(2, 1, 2, 1)]);
|
||||
executeAction(deleteAllLeftAction, editor);
|
||||
assert.equal(model.getLinesContent()[0], 'onetwothree');
|
||||
assert.equal(model.getLinesContent().length, 1);
|
||||
assert.strictEqual(model.getLinesContent()[0], 'onetwothree');
|
||||
assert.strictEqual(model.getLinesContent().length, 1);
|
||||
|
||||
editor.setSelection(new Selection(1, 1, 1, 1));
|
||||
executeAction(deleteAllLeftAction, editor);
|
||||
assert.equal(model.getLinesContent()[0], 'onetwothree');
|
||||
assert.strictEqual(model.getLinesContent()[0], 'onetwothree');
|
||||
});
|
||||
});
|
||||
|
||||
@@ -213,25 +213,25 @@ suite('Editor Contrib - Line Operations', () => {
|
||||
executeAction(deleteAllLeftAction, editor);
|
||||
let selections = editor.getSelections()!;
|
||||
|
||||
assert.equal(model.getLineContent(2), '');
|
||||
assert.equal(model.getLineContent(3), ' waso waso');
|
||||
assert.equal(model.getLineContent(5), '');
|
||||
assert.strictEqual(model.getLineContent(2), '');
|
||||
assert.strictEqual(model.getLineContent(3), ' waso waso');
|
||||
assert.strictEqual(model.getLineContent(5), '');
|
||||
|
||||
assert.deepEqual([
|
||||
assert.deepStrictEqual([
|
||||
selections[0].startLineNumber,
|
||||
selections[0].startColumn,
|
||||
selections[0].endLineNumber,
|
||||
selections[0].endColumn
|
||||
], [3, 1, 3, 1]);
|
||||
|
||||
assert.deepEqual([
|
||||
assert.deepStrictEqual([
|
||||
selections[1].startLineNumber,
|
||||
selections[1].startColumn,
|
||||
selections[1].endLineNumber,
|
||||
selections[1].endColumn
|
||||
], [2, 1, 2, 1]);
|
||||
|
||||
assert.deepEqual([
|
||||
assert.deepStrictEqual([
|
||||
selections[2].startLineNumber,
|
||||
selections[2].startColumn,
|
||||
selections[2].endLineNumber,
|
||||
@@ -241,17 +241,17 @@ suite('Editor Contrib - Line Operations', () => {
|
||||
executeAction(deleteAllLeftAction, editor);
|
||||
selections = editor.getSelections()!;
|
||||
|
||||
assert.equal(model.getLineContent(1), 'hi my name is Carlos Matos waso waso');
|
||||
assert.equal(selections.length, 2);
|
||||
assert.strictEqual(model.getLineContent(1), 'hi my name is Carlos Matos waso waso');
|
||||
assert.strictEqual(selections.length, 2);
|
||||
|
||||
assert.deepEqual([
|
||||
assert.deepStrictEqual([
|
||||
selections[0].startLineNumber,
|
||||
selections[0].startColumn,
|
||||
selections[0].endLineNumber,
|
||||
selections[0].endColumn
|
||||
], [1, 27, 1, 27]);
|
||||
|
||||
assert.deepEqual([
|
||||
assert.deepStrictEqual([
|
||||
selections[1].startLineNumber,
|
||||
selections[1].startColumn,
|
||||
selections[1].endLineNumber,
|
||||
@@ -277,23 +277,23 @@ suite('Editor Contrib - Line Operations', () => {
|
||||
|
||||
editor.setSelections([new Selection(1, 2, 1, 2), new Selection(1, 4, 1, 4)]);
|
||||
executeAction(deleteAllLeftAction, editor);
|
||||
assert.equal(model.getLineContent(1), 'lo');
|
||||
assert.strictEqual(model.getLineContent(1), 'lo');
|
||||
|
||||
editor.setSelections([new Selection(2, 2, 2, 2), new Selection(2, 4, 2, 5)]);
|
||||
executeAction(deleteAllLeftAction, editor);
|
||||
assert.equal(model.getLineContent(2), 'd');
|
||||
assert.strictEqual(model.getLineContent(2), 'd');
|
||||
|
||||
editor.setSelections([new Selection(3, 2, 3, 5), new Selection(3, 7, 3, 7)]);
|
||||
executeAction(deleteAllLeftAction, editor);
|
||||
assert.equal(model.getLineContent(3), 'world');
|
||||
assert.strictEqual(model.getLineContent(3), 'world');
|
||||
|
||||
editor.setSelections([new Selection(4, 3, 4, 3), new Selection(4, 5, 5, 4)]);
|
||||
executeAction(deleteAllLeftAction, editor);
|
||||
assert.equal(model.getLineContent(4), 'jour');
|
||||
assert.strictEqual(model.getLineContent(4), 'jour');
|
||||
|
||||
editor.setSelections([new Selection(5, 3, 6, 3), new Selection(6, 5, 7, 5), new Selection(7, 7, 7, 7)]);
|
||||
executeAction(deleteAllLeftAction, editor);
|
||||
assert.equal(model.getLineContent(5), 'world');
|
||||
assert.strictEqual(model.getLineContent(5), 'world');
|
||||
});
|
||||
});
|
||||
|
||||
@@ -310,16 +310,16 @@ suite('Editor Contrib - Line Operations', () => {
|
||||
editor.setSelection(new Selection(1, 1, 1, 1));
|
||||
|
||||
editor.trigger('keyboard', Handler.Type, { text: 'Typing some text here on line ' });
|
||||
assert.equal(model.getLineContent(1), 'Typing some text here on line one');
|
||||
assert.deepEqual(editor.getSelection(), new Selection(1, 31, 1, 31));
|
||||
assert.strictEqual(model.getLineContent(1), 'Typing some text here on line one');
|
||||
assert.deepStrictEqual(editor.getSelection(), new Selection(1, 31, 1, 31));
|
||||
|
||||
executeAction(deleteAllLeftAction, editor);
|
||||
assert.equal(model.getLineContent(1), 'one');
|
||||
assert.deepEqual(editor.getSelection(), new Selection(1, 1, 1, 1));
|
||||
assert.strictEqual(model.getLineContent(1), 'one');
|
||||
assert.deepStrictEqual(editor.getSelection(), new Selection(1, 1, 1, 1));
|
||||
|
||||
CoreEditingCommands.Undo.runEditorCommand(null, editor, null);
|
||||
assert.equal(model.getLineContent(1), 'Typing some text here on line one');
|
||||
assert.deepEqual(editor.getSelection(), new Selection(1, 31, 1, 31));
|
||||
assert.strictEqual(model.getLineContent(1), 'Typing some text here on line one');
|
||||
assert.deepStrictEqual(editor.getSelection(), new Selection(1, 31, 1, 31));
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -345,27 +345,27 @@ suite('Editor Contrib - Line Operations', () => {
|
||||
|
||||
editor.setSelection(new Selection(1, 2, 1, 2));
|
||||
executeAction(joinLinesAction, editor);
|
||||
assert.equal(model.getLineContent(1), 'hello world');
|
||||
assert.strictEqual(model.getLineContent(1), 'hello world');
|
||||
assertSelection(editor, new Selection(1, 6, 1, 6));
|
||||
|
||||
editor.setSelection(new Selection(2, 2, 2, 2));
|
||||
executeAction(joinLinesAction, editor);
|
||||
assert.equal(model.getLineContent(2), 'hello world');
|
||||
assert.strictEqual(model.getLineContent(2), 'hello world');
|
||||
assertSelection(editor, new Selection(2, 7, 2, 7));
|
||||
|
||||
editor.setSelection(new Selection(3, 2, 3, 2));
|
||||
executeAction(joinLinesAction, editor);
|
||||
assert.equal(model.getLineContent(3), 'hello world');
|
||||
assert.strictEqual(model.getLineContent(3), 'hello world');
|
||||
assertSelection(editor, new Selection(3, 7, 3, 7));
|
||||
|
||||
editor.setSelection(new Selection(4, 2, 5, 3));
|
||||
executeAction(joinLinesAction, editor);
|
||||
assert.equal(model.getLineContent(4), 'hello world');
|
||||
assert.strictEqual(model.getLineContent(4), 'hello world');
|
||||
assertSelection(editor, new Selection(4, 2, 4, 8));
|
||||
|
||||
editor.setSelection(new Selection(5, 1, 7, 3));
|
||||
executeAction(joinLinesAction, editor);
|
||||
assert.equal(model.getLineContent(5), 'hello world');
|
||||
assert.strictEqual(model.getLineContent(5), 'hello world');
|
||||
assertSelection(editor, new Selection(5, 1, 5, 3));
|
||||
});
|
||||
});
|
||||
@@ -381,8 +381,8 @@ suite('Editor Contrib - Line Operations', () => {
|
||||
|
||||
editor.setSelection(new Selection(2, 1, 2, 1));
|
||||
executeAction(joinLinesAction, editor);
|
||||
assert.equal(model.getLineContent(1), 'hello');
|
||||
assert.equal(model.getLineContent(2), 'world');
|
||||
assert.strictEqual(model.getLineContent(1), 'hello');
|
||||
assert.strictEqual(model.getLineContent(2), 'world');
|
||||
assertSelection(editor, new Selection(2, 6, 2, 6));
|
||||
});
|
||||
});
|
||||
@@ -416,7 +416,7 @@ suite('Editor Contrib - Line Operations', () => {
|
||||
]);
|
||||
|
||||
executeAction(joinLinesAction, editor);
|
||||
assert.equal(model.getLinesContent().join('\n'), 'hello world\nhello world\nhello world\nhello world\n\nhello world');
|
||||
assert.strictEqual(model.getLinesContent().join('\n'), 'hello world\nhello world\nhello world\nhello world\n\nhello world');
|
||||
assertSelection(editor, [
|
||||
/** primary cursor */
|
||||
new Selection(3, 4, 3, 8),
|
||||
@@ -440,16 +440,16 @@ suite('Editor Contrib - Line Operations', () => {
|
||||
editor.setSelection(new Selection(1, 6, 1, 6));
|
||||
|
||||
editor.trigger('keyboard', Handler.Type, { text: ' my dear' });
|
||||
assert.equal(model.getLineContent(1), 'hello my dear');
|
||||
assert.deepEqual(editor.getSelection(), new Selection(1, 14, 1, 14));
|
||||
assert.strictEqual(model.getLineContent(1), 'hello my dear');
|
||||
assert.deepStrictEqual(editor.getSelection(), new Selection(1, 14, 1, 14));
|
||||
|
||||
executeAction(joinLinesAction, editor);
|
||||
assert.equal(model.getLineContent(1), 'hello my dear world');
|
||||
assert.deepEqual(editor.getSelection(), new Selection(1, 14, 1, 14));
|
||||
assert.strictEqual(model.getLineContent(1), 'hello my dear world');
|
||||
assert.deepStrictEqual(editor.getSelection(), new Selection(1, 14, 1, 14));
|
||||
|
||||
CoreEditingCommands.Undo.runEditorCommand(null, editor, null);
|
||||
assert.equal(model.getLineContent(1), 'hello my dear');
|
||||
assert.deepEqual(editor.getSelection(), new Selection(1, 14, 1, 14));
|
||||
assert.strictEqual(model.getLineContent(1), 'hello my dear');
|
||||
assert.deepStrictEqual(editor.getSelection(), new Selection(1, 14, 1, 14));
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -467,27 +467,27 @@ suite('Editor Contrib - Line Operations', () => {
|
||||
|
||||
editor.setSelection(new Selection(1, 1, 1, 1));
|
||||
executeAction(transposeAction, editor);
|
||||
assert.equal(model.getLineContent(1), 'hello world');
|
||||
assert.strictEqual(model.getLineContent(1), 'hello world');
|
||||
assertSelection(editor, new Selection(1, 2, 1, 2));
|
||||
|
||||
editor.setSelection(new Selection(1, 6, 1, 6));
|
||||
executeAction(transposeAction, editor);
|
||||
assert.equal(model.getLineContent(1), 'hell oworld');
|
||||
assert.strictEqual(model.getLineContent(1), 'hell oworld');
|
||||
assertSelection(editor, new Selection(1, 7, 1, 7));
|
||||
|
||||
editor.setSelection(new Selection(1, 12, 1, 12));
|
||||
executeAction(transposeAction, editor);
|
||||
assert.equal(model.getLineContent(1), 'hell oworl');
|
||||
assert.strictEqual(model.getLineContent(1), 'hell oworl');
|
||||
assertSelection(editor, new Selection(2, 2, 2, 2));
|
||||
|
||||
editor.setSelection(new Selection(3, 1, 3, 1));
|
||||
executeAction(transposeAction, editor);
|
||||
assert.equal(model.getLineContent(3), '');
|
||||
assert.strictEqual(model.getLineContent(3), '');
|
||||
assertSelection(editor, new Selection(4, 1, 4, 1));
|
||||
|
||||
editor.setSelection(new Selection(4, 2, 4, 2));
|
||||
executeAction(transposeAction, editor);
|
||||
assert.equal(model.getLineContent(4), ' ');
|
||||
assert.strictEqual(model.getLineContent(4), ' ');
|
||||
assertSelection(editor, new Selection(4, 3, 4, 3));
|
||||
}
|
||||
);
|
||||
@@ -509,22 +509,22 @@ suite('Editor Contrib - Line Operations', () => {
|
||||
|
||||
editor.setSelection(new Selection(1, 1, 1, 1));
|
||||
executeAction(transposeAction, editor);
|
||||
assert.equal(model.getLineContent(2), '');
|
||||
assert.strictEqual(model.getLineContent(2), '');
|
||||
assertSelection(editor, new Selection(2, 1, 2, 1));
|
||||
|
||||
editor.setSelection(new Selection(3, 6, 3, 6));
|
||||
executeAction(transposeAction, editor);
|
||||
assert.equal(model.getLineContent(4), 'oworld');
|
||||
assert.strictEqual(model.getLineContent(4), 'oworld');
|
||||
assertSelection(editor, new Selection(4, 2, 4, 2));
|
||||
|
||||
editor.setSelection(new Selection(6, 12, 6, 12));
|
||||
executeAction(transposeAction, editor);
|
||||
assert.equal(model.getLineContent(7), 'd');
|
||||
assert.strictEqual(model.getLineContent(7), 'd');
|
||||
assertSelection(editor, new Selection(7, 2, 7, 2));
|
||||
|
||||
editor.setSelection(new Selection(8, 12, 8, 12));
|
||||
executeAction(transposeAction, editor);
|
||||
assert.equal(model.getLineContent(8), 'hello world');
|
||||
assert.strictEqual(model.getLineContent(8), 'hello world');
|
||||
assertSelection(editor, new Selection(8, 12, 8, 12));
|
||||
}
|
||||
);
|
||||
@@ -534,52 +534,131 @@ suite('Editor Contrib - Line Operations', () => {
|
||||
withTestCodeEditor(
|
||||
[
|
||||
'hello world',
|
||||
'öçşğü'
|
||||
'öçşğü',
|
||||
'parseHTMLString',
|
||||
'getElementById',
|
||||
'insertHTML',
|
||||
'PascalCase',
|
||||
'CSSSelectorsList',
|
||||
'iD',
|
||||
'tEST',
|
||||
'öçşÖÇŞğüĞÜ',
|
||||
'audioConverter.convertM4AToMP3();',
|
||||
'snake_case',
|
||||
'Capital_Snake_Case',
|
||||
`function helloWorld() {
|
||||
return someGlobalObject.printHelloWorld("en", "utf-8");
|
||||
}
|
||||
helloWorld();`.replace(/^\s+/gm, '')
|
||||
], {}, (editor) => {
|
||||
let model = editor.getModel()!;
|
||||
let uppercaseAction = new UpperCaseAction();
|
||||
let lowercaseAction = new LowerCaseAction();
|
||||
let titlecaseAction = new TitleCaseAction();
|
||||
let snakecaseAction = new SnakeCaseAction();
|
||||
|
||||
editor.setSelection(new Selection(1, 1, 1, 12));
|
||||
executeAction(uppercaseAction, editor);
|
||||
assert.equal(model.getLineContent(1), 'HELLO WORLD');
|
||||
assert.strictEqual(model.getLineContent(1), 'HELLO WORLD');
|
||||
assertSelection(editor, new Selection(1, 1, 1, 12));
|
||||
|
||||
editor.setSelection(new Selection(1, 1, 1, 12));
|
||||
executeAction(lowercaseAction, editor);
|
||||
assert.equal(model.getLineContent(1), 'hello world');
|
||||
assert.strictEqual(model.getLineContent(1), 'hello world');
|
||||
assertSelection(editor, new Selection(1, 1, 1, 12));
|
||||
|
||||
editor.setSelection(new Selection(1, 3, 1, 3));
|
||||
executeAction(uppercaseAction, editor);
|
||||
assert.equal(model.getLineContent(1), 'HELLO world');
|
||||
assert.strictEqual(model.getLineContent(1), 'HELLO world');
|
||||
assertSelection(editor, new Selection(1, 3, 1, 3));
|
||||
|
||||
editor.setSelection(new Selection(1, 4, 1, 4));
|
||||
executeAction(lowercaseAction, editor);
|
||||
assert.equal(model.getLineContent(1), 'hello world');
|
||||
assert.strictEqual(model.getLineContent(1), 'hello world');
|
||||
assertSelection(editor, new Selection(1, 4, 1, 4));
|
||||
|
||||
editor.setSelection(new Selection(1, 1, 1, 12));
|
||||
executeAction(titlecaseAction, editor);
|
||||
assert.equal(model.getLineContent(1), 'Hello World');
|
||||
assert.strictEqual(model.getLineContent(1), 'Hello World');
|
||||
assertSelection(editor, new Selection(1, 1, 1, 12));
|
||||
|
||||
editor.setSelection(new Selection(2, 1, 2, 6));
|
||||
executeAction(uppercaseAction, editor);
|
||||
assert.equal(model.getLineContent(2), 'ÖÇŞĞÜ');
|
||||
assert.strictEqual(model.getLineContent(2), 'ÖÇŞĞÜ');
|
||||
assertSelection(editor, new Selection(2, 1, 2, 6));
|
||||
|
||||
editor.setSelection(new Selection(2, 1, 2, 6));
|
||||
executeAction(lowercaseAction, editor);
|
||||
assert.equal(model.getLineContent(2), 'öçşğü');
|
||||
assert.strictEqual(model.getLineContent(2), 'öçşğü');
|
||||
assertSelection(editor, new Selection(2, 1, 2, 6));
|
||||
|
||||
editor.setSelection(new Selection(2, 1, 2, 6));
|
||||
executeAction(titlecaseAction, editor);
|
||||
assert.equal(model.getLineContent(2), 'Öçşğü');
|
||||
assert.strictEqual(model.getLineContent(2), 'Öçşğü');
|
||||
assertSelection(editor, new Selection(2, 1, 2, 6));
|
||||
|
||||
editor.setSelection(new Selection(3, 1, 3, 16));
|
||||
executeAction(snakecaseAction, editor);
|
||||
assert.strictEqual(model.getLineContent(3), 'parse_html_string');
|
||||
assertSelection(editor, new Selection(3, 1, 3, 18));
|
||||
|
||||
editor.setSelection(new Selection(4, 1, 4, 15));
|
||||
executeAction(snakecaseAction, editor);
|
||||
assert.strictEqual(model.getLineContent(4), 'get_element_by_id');
|
||||
assertSelection(editor, new Selection(4, 1, 4, 18));
|
||||
|
||||
editor.setSelection(new Selection(5, 1, 5, 11));
|
||||
executeAction(snakecaseAction, editor);
|
||||
assert.strictEqual(model.getLineContent(5), 'insert_html');
|
||||
assertSelection(editor, new Selection(5, 1, 5, 12));
|
||||
|
||||
editor.setSelection(new Selection(6, 1, 6, 11));
|
||||
executeAction(snakecaseAction, editor);
|
||||
assert.strictEqual(model.getLineContent(6), 'pascal_case');
|
||||
assertSelection(editor, new Selection(6, 1, 6, 12));
|
||||
|
||||
editor.setSelection(new Selection(7, 1, 7, 17));
|
||||
executeAction(snakecaseAction, editor);
|
||||
assert.strictEqual(model.getLineContent(7), 'css_selectors_list');
|
||||
assertSelection(editor, new Selection(7, 1, 7, 19));
|
||||
|
||||
editor.setSelection(new Selection(8, 1, 8, 3));
|
||||
executeAction(snakecaseAction, editor);
|
||||
assert.strictEqual(model.getLineContent(8), 'i_d');
|
||||
assertSelection(editor, new Selection(8, 1, 8, 4));
|
||||
|
||||
editor.setSelection(new Selection(9, 1, 9, 5));
|
||||
executeAction(snakecaseAction, editor);
|
||||
assert.strictEqual(model.getLineContent(9), 't_est');
|
||||
assertSelection(editor, new Selection(9, 1, 9, 6));
|
||||
|
||||
editor.setSelection(new Selection(10, 1, 10, 11));
|
||||
executeAction(snakecaseAction, editor);
|
||||
assert.strictEqual(model.getLineContent(10), 'öçş_öç_şğü_ğü');
|
||||
assertSelection(editor, new Selection(10, 1, 10, 14));
|
||||
|
||||
editor.setSelection(new Selection(11, 1, 11, 34));
|
||||
executeAction(snakecaseAction, editor);
|
||||
assert.strictEqual(model.getLineContent(11), 'audio_converter.convert_m4a_to_mp3();');
|
||||
assertSelection(editor, new Selection(11, 1, 11, 38));
|
||||
|
||||
editor.setSelection(new Selection(12, 1, 12, 11));
|
||||
executeAction(snakecaseAction, editor);
|
||||
assert.strictEqual(model.getLineContent(12), 'snake_case');
|
||||
assertSelection(editor, new Selection(12, 1, 12, 11));
|
||||
|
||||
editor.setSelection(new Selection(13, 1, 13, 19));
|
||||
executeAction(snakecaseAction, editor);
|
||||
assert.strictEqual(model.getLineContent(13), 'capital_snake_case');
|
||||
assertSelection(editor, new Selection(13, 1, 13, 19));
|
||||
|
||||
editor.setSelection(new Selection(14, 1, 17, 14));
|
||||
executeAction(snakecaseAction, editor);
|
||||
assert.strictEqual(model.getValueInRange(new Selection(14, 1, 17, 15)), `function hello_world() {
|
||||
return some_global_object.print_hello_world("en", "utf-8");
|
||||
}
|
||||
hello_world();`.replace(/^\s+/gm, ''));
|
||||
assertSelection(editor, new Selection(14, 1, 17, 15));
|
||||
}
|
||||
);
|
||||
|
||||
@@ -597,27 +676,27 @@ suite('Editor Contrib - Line Operations', () => {
|
||||
|
||||
editor.setSelection(new Selection(1, 1, 1, 12));
|
||||
executeAction(titlecaseAction, editor);
|
||||
assert.equal(model.getLineContent(1), 'Foo Bar Baz');
|
||||
assert.strictEqual(model.getLineContent(1), 'Foo Bar Baz');
|
||||
|
||||
editor.setSelection(new Selection(2, 1, 2, 12));
|
||||
executeAction(titlecaseAction, editor);
|
||||
assert.equal(model.getLineContent(2), 'Foo\'Bar\'Baz');
|
||||
assert.strictEqual(model.getLineContent(2), 'Foo\'Bar\'Baz');
|
||||
|
||||
editor.setSelection(new Selection(3, 1, 3, 12));
|
||||
executeAction(titlecaseAction, editor);
|
||||
assert.equal(model.getLineContent(3), 'Foo[Bar]Baz');
|
||||
assert.strictEqual(model.getLineContent(3), 'Foo[Bar]Baz');
|
||||
|
||||
editor.setSelection(new Selection(4, 1, 4, 12));
|
||||
executeAction(titlecaseAction, editor);
|
||||
assert.equal(model.getLineContent(4), 'Foo`Bar~Baz');
|
||||
assert.strictEqual(model.getLineContent(4), 'Foo`Bar~Baz');
|
||||
|
||||
editor.setSelection(new Selection(5, 1, 5, 12));
|
||||
executeAction(titlecaseAction, editor);
|
||||
assert.equal(model.getLineContent(5), 'Foo^Bar%Baz');
|
||||
assert.strictEqual(model.getLineContent(5), 'Foo^Bar%Baz');
|
||||
|
||||
editor.setSelection(new Selection(6, 1, 6, 12));
|
||||
executeAction(titlecaseAction, editor);
|
||||
assert.equal(model.getLineContent(6), 'Foo$Bar!Baz');
|
||||
assert.strictEqual(model.getLineContent(6), 'Foo$Bar!Baz');
|
||||
}
|
||||
);
|
||||
|
||||
@@ -632,22 +711,22 @@ suite('Editor Contrib - Line Operations', () => {
|
||||
|
||||
editor.setSelection(new Selection(1, 1, 1, 1));
|
||||
executeAction(uppercaseAction, editor);
|
||||
assert.equal(model.getLineContent(1), '');
|
||||
assert.strictEqual(model.getLineContent(1), '');
|
||||
assertSelection(editor, new Selection(1, 1, 1, 1));
|
||||
|
||||
editor.setSelection(new Selection(1, 1, 1, 1));
|
||||
executeAction(lowercaseAction, editor);
|
||||
assert.equal(model.getLineContent(1), '');
|
||||
assert.strictEqual(model.getLineContent(1), '');
|
||||
assertSelection(editor, new Selection(1, 1, 1, 1));
|
||||
|
||||
editor.setSelection(new Selection(2, 2, 2, 2));
|
||||
executeAction(uppercaseAction, editor);
|
||||
assert.equal(model.getLineContent(2), ' ');
|
||||
assert.strictEqual(model.getLineContent(2), ' ');
|
||||
assertSelection(editor, new Selection(2, 2, 2, 2));
|
||||
|
||||
editor.setSelection(new Selection(2, 2, 2, 2));
|
||||
executeAction(lowercaseAction, editor);
|
||||
assert.equal(model.getLineContent(2), ' ');
|
||||
assert.strictEqual(model.getLineContent(2), ' ');
|
||||
assertSelection(editor, new Selection(2, 2, 2, 2));
|
||||
}
|
||||
);
|
||||
@@ -660,18 +739,18 @@ suite('Editor Contrib - Line Operations', () => {
|
||||
const action = new DeleteAllRightAction();
|
||||
|
||||
executeAction(action, editor);
|
||||
assert.deepEqual(model.getLinesContent(), ['']);
|
||||
assert.deepEqual(editor.getSelections(), [new Selection(1, 1, 1, 1)]);
|
||||
assert.deepStrictEqual(model.getLinesContent(), ['']);
|
||||
assert.deepStrictEqual(editor.getSelections(), [new Selection(1, 1, 1, 1)]);
|
||||
|
||||
editor.setSelection(new Selection(1, 1, 1, 1));
|
||||
executeAction(action, editor);
|
||||
assert.deepEqual(model.getLinesContent(), ['']);
|
||||
assert.deepEqual(editor.getSelections(), [new Selection(1, 1, 1, 1)]);
|
||||
assert.deepStrictEqual(model.getLinesContent(), ['']);
|
||||
assert.deepStrictEqual(editor.getSelections(), [new Selection(1, 1, 1, 1)]);
|
||||
|
||||
editor.setSelections([new Selection(1, 1, 1, 1), new Selection(1, 1, 1, 1), new Selection(1, 1, 1, 1)]);
|
||||
executeAction(action, editor);
|
||||
assert.deepEqual(model.getLinesContent(), ['']);
|
||||
assert.deepEqual(editor.getSelections(), [new Selection(1, 1, 1, 1)]);
|
||||
assert.deepStrictEqual(model.getLinesContent(), ['']);
|
||||
assert.deepStrictEqual(editor.getSelections(), [new Selection(1, 1, 1, 1)]);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -685,18 +764,18 @@ suite('Editor Contrib - Line Operations', () => {
|
||||
|
||||
editor.setSelection(new Selection(1, 2, 1, 5));
|
||||
executeAction(action, editor);
|
||||
assert.deepEqual(model.getLinesContent(), ['ho', 'world']);
|
||||
assert.deepEqual(editor.getSelections(), [new Selection(1, 2, 1, 2)]);
|
||||
assert.deepStrictEqual(model.getLinesContent(), ['ho', 'world']);
|
||||
assert.deepStrictEqual(editor.getSelections(), [new Selection(1, 2, 1, 2)]);
|
||||
|
||||
editor.setSelection(new Selection(1, 1, 2, 4));
|
||||
executeAction(action, editor);
|
||||
assert.deepEqual(model.getLinesContent(), ['ld']);
|
||||
assert.deepEqual(editor.getSelections(), [new Selection(1, 1, 1, 1)]);
|
||||
assert.deepStrictEqual(model.getLinesContent(), ['ld']);
|
||||
assert.deepStrictEqual(editor.getSelections(), [new Selection(1, 1, 1, 1)]);
|
||||
|
||||
editor.setSelection(new Selection(1, 1, 1, 3));
|
||||
executeAction(action, editor);
|
||||
assert.deepEqual(model.getLinesContent(), ['']);
|
||||
assert.deepEqual(editor.getSelections(), [new Selection(1, 1, 1, 1)]);
|
||||
assert.deepStrictEqual(model.getLinesContent(), ['']);
|
||||
assert.deepStrictEqual(editor.getSelections(), [new Selection(1, 1, 1, 1)]);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -710,13 +789,13 @@ suite('Editor Contrib - Line Operations', () => {
|
||||
|
||||
editor.setSelection(new Selection(1, 3, 1, 3));
|
||||
executeAction(action, editor);
|
||||
assert.deepEqual(model.getLinesContent(), ['he', 'world']);
|
||||
assert.deepEqual(editor.getSelections(), [new Selection(1, 3, 1, 3)]);
|
||||
assert.deepStrictEqual(model.getLinesContent(), ['he', 'world']);
|
||||
assert.deepStrictEqual(editor.getSelections(), [new Selection(1, 3, 1, 3)]);
|
||||
|
||||
editor.setSelection(new Selection(2, 1, 2, 1));
|
||||
executeAction(action, editor);
|
||||
assert.deepEqual(model.getLinesContent(), ['he', '']);
|
||||
assert.deepEqual(editor.getSelections(), [new Selection(2, 1, 2, 1)]);
|
||||
assert.deepStrictEqual(model.getLinesContent(), ['he', '']);
|
||||
assert.deepStrictEqual(editor.getSelections(), [new Selection(2, 1, 2, 1)]);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -730,18 +809,18 @@ suite('Editor Contrib - Line Operations', () => {
|
||||
|
||||
editor.setSelection(new Selection(1, 6, 1, 6));
|
||||
executeAction(action, editor);
|
||||
assert.deepEqual(model.getLinesContent(), ['helloworld']);
|
||||
assert.deepEqual(editor.getSelections(), [new Selection(1, 6, 1, 6)]);
|
||||
assert.deepStrictEqual(model.getLinesContent(), ['helloworld']);
|
||||
assert.deepStrictEqual(editor.getSelections(), [new Selection(1, 6, 1, 6)]);
|
||||
|
||||
editor.setSelection(new Selection(1, 6, 1, 6));
|
||||
executeAction(action, editor);
|
||||
assert.deepEqual(model.getLinesContent(), ['hello']);
|
||||
assert.deepEqual(editor.getSelections(), [new Selection(1, 6, 1, 6)]);
|
||||
assert.deepStrictEqual(model.getLinesContent(), ['hello']);
|
||||
assert.deepStrictEqual(editor.getSelections(), [new Selection(1, 6, 1, 6)]);
|
||||
|
||||
editor.setSelection(new Selection(1, 6, 1, 6));
|
||||
executeAction(action, editor);
|
||||
assert.deepEqual(model.getLinesContent(), ['hello']);
|
||||
assert.deepEqual(editor.getSelections(), [new Selection(1, 6, 1, 6)]);
|
||||
assert.deepStrictEqual(model.getLinesContent(), ['hello']);
|
||||
assert.deepStrictEqual(editor.getSelections(), [new Selection(1, 6, 1, 6)]);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -760,35 +839,35 @@ suite('Editor Contrib - Line Operations', () => {
|
||||
new Selection(3, 4, 3, 4),
|
||||
]);
|
||||
executeAction(action, editor);
|
||||
assert.deepEqual(model.getLinesContent(), ['hethere', 'wor']);
|
||||
assert.deepEqual(editor.getSelections(), [
|
||||
assert.deepStrictEqual(model.getLinesContent(), ['hethere', 'wor']);
|
||||
assert.deepStrictEqual(editor.getSelections(), [
|
||||
new Selection(1, 3, 1, 3),
|
||||
new Selection(2, 4, 2, 4)
|
||||
]);
|
||||
|
||||
executeAction(action, editor);
|
||||
assert.deepEqual(model.getLinesContent(), ['he', 'wor']);
|
||||
assert.deepEqual(editor.getSelections(), [
|
||||
assert.deepStrictEqual(model.getLinesContent(), ['he', 'wor']);
|
||||
assert.deepStrictEqual(editor.getSelections(), [
|
||||
new Selection(1, 3, 1, 3),
|
||||
new Selection(2, 4, 2, 4)
|
||||
]);
|
||||
|
||||
executeAction(action, editor);
|
||||
assert.deepEqual(model.getLinesContent(), ['hewor']);
|
||||
assert.deepEqual(editor.getSelections(), [
|
||||
assert.deepStrictEqual(model.getLinesContent(), ['hewor']);
|
||||
assert.deepStrictEqual(editor.getSelections(), [
|
||||
new Selection(1, 3, 1, 3),
|
||||
new Selection(1, 6, 1, 6)
|
||||
]);
|
||||
|
||||
executeAction(action, editor);
|
||||
assert.deepEqual(model.getLinesContent(), ['he']);
|
||||
assert.deepEqual(editor.getSelections(), [
|
||||
assert.deepStrictEqual(model.getLinesContent(), ['he']);
|
||||
assert.deepStrictEqual(editor.getSelections(), [
|
||||
new Selection(1, 3, 1, 3)
|
||||
]);
|
||||
|
||||
executeAction(action, editor);
|
||||
assert.deepEqual(model.getLinesContent(), ['he']);
|
||||
assert.deepEqual(editor.getSelections(), [
|
||||
assert.deepStrictEqual(model.getLinesContent(), ['he']);
|
||||
assert.deepStrictEqual(editor.getSelections(), [
|
||||
new Selection(1, 3, 1, 3)
|
||||
]);
|
||||
});
|
||||
@@ -809,20 +888,20 @@ suite('Editor Contrib - Line Operations', () => {
|
||||
new Selection(3, 4, 3, 4),
|
||||
]);
|
||||
executeAction(action, editor);
|
||||
assert.deepEqual(model.getLinesContent(), ['hethere', 'wor']);
|
||||
assert.deepEqual(editor.getSelections(), [
|
||||
assert.deepStrictEqual(model.getLinesContent(), ['hethere', 'wor']);
|
||||
assert.deepStrictEqual(editor.getSelections(), [
|
||||
new Selection(1, 3, 1, 3),
|
||||
new Selection(2, 4, 2, 4)
|
||||
]);
|
||||
|
||||
CoreEditingCommands.Undo.runEditorCommand(null, editor, null);
|
||||
assert.deepEqual(editor.getSelections(), [
|
||||
assert.deepStrictEqual(editor.getSelections(), [
|
||||
new Selection(1, 3, 1, 3),
|
||||
new Selection(1, 6, 1, 6),
|
||||
new Selection(3, 4, 3, 4)
|
||||
]);
|
||||
CoreEditingCommands.Redo.runEditorCommand(null, editor, null);
|
||||
assert.deepEqual(editor.getSelections(), [
|
||||
assert.deepStrictEqual(editor.getSelections(), [
|
||||
new Selection(1, 3, 1, 3),
|
||||
new Selection(2, 4, 2, 4)
|
||||
]);
|
||||
@@ -847,27 +926,27 @@ suite('Editor Contrib - Line Operations', () => {
|
||||
}
|
||||
|
||||
testInsertLineBefore(1, 3, (model, viewModel) => {
|
||||
assert.deepEqual(viewModel.getSelection(), new Selection(1, 1, 1, 1));
|
||||
assert.equal(model.getLineContent(1), '');
|
||||
assert.equal(model.getLineContent(2), 'First line');
|
||||
assert.equal(model.getLineContent(3), 'Second line');
|
||||
assert.equal(model.getLineContent(4), 'Third line');
|
||||
assert.deepStrictEqual(viewModel.getSelection(), new Selection(1, 1, 1, 1));
|
||||
assert.strictEqual(model.getLineContent(1), '');
|
||||
assert.strictEqual(model.getLineContent(2), 'First line');
|
||||
assert.strictEqual(model.getLineContent(3), 'Second line');
|
||||
assert.strictEqual(model.getLineContent(4), 'Third line');
|
||||
});
|
||||
|
||||
testInsertLineBefore(2, 3, (model, viewModel) => {
|
||||
assert.deepEqual(viewModel.getSelection(), new Selection(2, 1, 2, 1));
|
||||
assert.equal(model.getLineContent(1), 'First line');
|
||||
assert.equal(model.getLineContent(2), '');
|
||||
assert.equal(model.getLineContent(3), 'Second line');
|
||||
assert.equal(model.getLineContent(4), 'Third line');
|
||||
assert.deepStrictEqual(viewModel.getSelection(), new Selection(2, 1, 2, 1));
|
||||
assert.strictEqual(model.getLineContent(1), 'First line');
|
||||
assert.strictEqual(model.getLineContent(2), '');
|
||||
assert.strictEqual(model.getLineContent(3), 'Second line');
|
||||
assert.strictEqual(model.getLineContent(4), 'Third line');
|
||||
});
|
||||
|
||||
testInsertLineBefore(3, 3, (model, viewModel) => {
|
||||
assert.deepEqual(viewModel.getSelection(), new Selection(3, 1, 3, 1));
|
||||
assert.equal(model.getLineContent(1), 'First line');
|
||||
assert.equal(model.getLineContent(2), 'Second line');
|
||||
assert.equal(model.getLineContent(3), '');
|
||||
assert.equal(model.getLineContent(4), 'Third line');
|
||||
assert.deepStrictEqual(viewModel.getSelection(), new Selection(3, 1, 3, 1));
|
||||
assert.strictEqual(model.getLineContent(1), 'First line');
|
||||
assert.strictEqual(model.getLineContent(2), 'Second line');
|
||||
assert.strictEqual(model.getLineContent(3), '');
|
||||
assert.strictEqual(model.getLineContent(4), 'Third line');
|
||||
});
|
||||
});
|
||||
|
||||
@@ -888,27 +967,27 @@ suite('Editor Contrib - Line Operations', () => {
|
||||
}
|
||||
|
||||
testInsertLineAfter(1, 3, (model, viewModel) => {
|
||||
assert.deepEqual(viewModel.getSelection(), new Selection(2, 1, 2, 1));
|
||||
assert.equal(model.getLineContent(1), 'First line');
|
||||
assert.equal(model.getLineContent(2), '');
|
||||
assert.equal(model.getLineContent(3), 'Second line');
|
||||
assert.equal(model.getLineContent(4), 'Third line');
|
||||
assert.deepStrictEqual(viewModel.getSelection(), new Selection(2, 1, 2, 1));
|
||||
assert.strictEqual(model.getLineContent(1), 'First line');
|
||||
assert.strictEqual(model.getLineContent(2), '');
|
||||
assert.strictEqual(model.getLineContent(3), 'Second line');
|
||||
assert.strictEqual(model.getLineContent(4), 'Third line');
|
||||
});
|
||||
|
||||
testInsertLineAfter(2, 3, (model, viewModel) => {
|
||||
assert.deepEqual(viewModel.getSelection(), new Selection(3, 1, 3, 1));
|
||||
assert.equal(model.getLineContent(1), 'First line');
|
||||
assert.equal(model.getLineContent(2), 'Second line');
|
||||
assert.equal(model.getLineContent(3), '');
|
||||
assert.equal(model.getLineContent(4), 'Third line');
|
||||
assert.deepStrictEqual(viewModel.getSelection(), new Selection(3, 1, 3, 1));
|
||||
assert.strictEqual(model.getLineContent(1), 'First line');
|
||||
assert.strictEqual(model.getLineContent(2), 'Second line');
|
||||
assert.strictEqual(model.getLineContent(3), '');
|
||||
assert.strictEqual(model.getLineContent(4), 'Third line');
|
||||
});
|
||||
|
||||
testInsertLineAfter(3, 3, (model, viewModel) => {
|
||||
assert.deepEqual(viewModel.getSelection(), new Selection(4, 1, 4, 1));
|
||||
assert.equal(model.getLineContent(1), 'First line');
|
||||
assert.equal(model.getLineContent(2), 'Second line');
|
||||
assert.equal(model.getLineContent(3), 'Third line');
|
||||
assert.equal(model.getLineContent(4), '');
|
||||
assert.deepStrictEqual(viewModel.getSelection(), new Selection(4, 1, 4, 1));
|
||||
assert.strictEqual(model.getLineContent(1), 'First line');
|
||||
assert.strictEqual(model.getLineContent(2), 'Second line');
|
||||
assert.strictEqual(model.getLineContent(3), 'Third line');
|
||||
assert.strictEqual(model.getLineContent(4), '');
|
||||
});
|
||||
});
|
||||
|
||||
@@ -928,11 +1007,11 @@ suite('Editor Contrib - Line Operations', () => {
|
||||
editor.setPosition(new Position(1, 2));
|
||||
|
||||
executeAction(indentLinesAction, editor);
|
||||
assert.equal(model.getLineContent(1), '\tfunction baz() {');
|
||||
assert.deepEqual(editor.getSelection(), new Selection(1, 3, 1, 3));
|
||||
assert.strictEqual(model.getLineContent(1), '\tfunction baz() {');
|
||||
assert.deepStrictEqual(editor.getSelection(), new Selection(1, 3, 1, 3));
|
||||
|
||||
CoreEditingCommands.Tab.runEditorCommand(null, editor, null);
|
||||
assert.equal(model.getLineContent(1), '\tf\tunction baz() {');
|
||||
assert.strictEqual(model.getLineContent(1), '\tf\tunction baz() {');
|
||||
});
|
||||
|
||||
model.dispose();
|
||||
@@ -953,8 +1032,8 @@ suite('Editor Contrib - Line Operations', () => {
|
||||
editor.setPosition(new Position(1, 1));
|
||||
|
||||
executeAction(indentLinesAction, editor);
|
||||
assert.equal(model.getLineContent(1), '\tSome text');
|
||||
assert.deepEqual(editor.getSelection(), new Selection(1, 2, 1, 2));
|
||||
assert.strictEqual(model.getLineContent(1), '\tSome text');
|
||||
assert.deepStrictEqual(editor.getSelection(), new Selection(1, 2, 1, 2));
|
||||
});
|
||||
|
||||
model.dispose();
|
||||
@@ -972,8 +1051,8 @@ suite('Editor Contrib - Line Operations', () => {
|
||||
editor.setPosition(new Position(1, 1));
|
||||
|
||||
executeAction(indentLinesAction, editor);
|
||||
assert.equal(model.getLineContent(1), ' ');
|
||||
assert.deepEqual(editor.getSelection(), new Selection(1, 5, 1, 5));
|
||||
assert.strictEqual(model.getLineContent(1), ' ');
|
||||
assert.deepStrictEqual(editor.getSelection(), new Selection(1, 5, 1, 5));
|
||||
});
|
||||
|
||||
model.dispose();
|
||||
@@ -995,7 +1074,7 @@ suite('Editor Contrib - Line Operations', () => {
|
||||
const deleteLinesAction = new DeleteLinesAction();
|
||||
executeAction(deleteLinesAction, editor);
|
||||
|
||||
assert.equal(editor.getValue(), 'a\nc');
|
||||
assert.strictEqual(editor.getValue(), 'a\nc');
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1007,8 +1086,8 @@ suite('Editor Contrib - Line Operations', () => {
|
||||
const deleteLinesAction = new DeleteLinesAction();
|
||||
executeAction(deleteLinesAction, editor);
|
||||
|
||||
assert.equal(editor.getValue(), resultingText.join('\n'));
|
||||
assert.deepEqual(editor.getSelections(), resultingSelections);
|
||||
assert.strictEqual(editor.getValue(), resultingText.join('\n'));
|
||||
assert.deepStrictEqual(editor.getSelections(), resultingSelections);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -57,7 +57,7 @@ function getHoverMessage(link: Link, useMetaKey: boolean): MarkdownString {
|
||||
nativeLabel = ` "${nativeLabelText}"`;
|
||||
}
|
||||
}
|
||||
const hoverMessage = new MarkdownString('', true).appendMarkdown(`[${label}](${link.url.toString()}${nativeLabel}) (${kb})`);
|
||||
const hoverMessage = new MarkdownString('', true).appendMarkdown(`[${label}](${link.url.toString(true)}${nativeLabel}) (${kb})`);
|
||||
return hoverMessage;
|
||||
} else {
|
||||
return new MarkdownString().appendText(`${label} (${kb})`);
|
||||
@@ -327,7 +327,7 @@ export class LinkDetector implements IEditorContribution {
|
||||
}
|
||||
}
|
||||
|
||||
return this.openerService.open(uri, { openToSide, fromUserGesture });
|
||||
return this.openerService.open(uri, { openToSide, fromUserGesture, allowContributedOpeners: true });
|
||||
|
||||
}, err => {
|
||||
const messageOrError =
|
||||
|
||||
@@ -850,7 +850,6 @@ export class SelectionHighlighter extends Disposable implements IEditorContribut
|
||||
this.updateSoon.schedule();
|
||||
} else {
|
||||
this._setState(null);
|
||||
|
||||
}
|
||||
} else {
|
||||
this._update();
|
||||
@@ -1016,11 +1015,6 @@ export class SelectionHighlighter extends Disposable implements IEditorContribut
|
||||
});
|
||||
|
||||
this.decorations = this.editor.deltaDecorations(this.decorations, decorations);
|
||||
|
||||
const currentFindState = CommonFindController.get(this.editor).getState();
|
||||
if (currentFindState.isRegex || currentFindState.matchCase || currentFindState.wholeWord) {
|
||||
CommonFindController.get(this.editor).highlightFindOptions(true);
|
||||
}
|
||||
}
|
||||
|
||||
private static readonly _SELECTION_HIGHLIGHT_OVERVIEW = ModelDecorationOptions.register({
|
||||
|
||||
@@ -25,7 +25,7 @@ suite('Multicursor', () => {
|
||||
|
||||
editor.setSelection(new Selection(2, 1, 2, 1));
|
||||
addCursorUpAction.run(null!, editor, {});
|
||||
assert.equal(viewModel.getSelections().length, 2);
|
||||
assert.strictEqual(viewModel.getSelections().length, 2);
|
||||
|
||||
editor.trigger('test', Handler.Paste, {
|
||||
text: '1\n2',
|
||||
@@ -35,8 +35,8 @@ suite('Multicursor', () => {
|
||||
]
|
||||
});
|
||||
|
||||
assert.equal(editor.getModel()!.getLineContent(1), '1abc');
|
||||
assert.equal(editor.getModel()!.getLineContent(2), '2def');
|
||||
assert.strictEqual(editor.getModel()!.getLineContent(1), '1abc');
|
||||
assert.strictEqual(editor.getModel()!.getLineContent(2), '2def');
|
||||
});
|
||||
});
|
||||
|
||||
@@ -46,7 +46,7 @@ suite('Multicursor', () => {
|
||||
], {}, (editor, viewModel) => {
|
||||
let addCursorDownAction = new InsertCursorBelow();
|
||||
addCursorDownAction.run(null!, editor, {});
|
||||
assert.equal(viewModel.getSelections().length, 1);
|
||||
assert.strictEqual(viewModel.getSelections().length, 1);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -90,7 +90,7 @@ suite('Multicursor selection', () => {
|
||||
editor.setSelection(new Selection(2, 9, 2, 16));
|
||||
|
||||
selectHighlightsAction.run(null!, editor);
|
||||
assert.deepEqual(editor.getSelections()!.map(fromRange), [
|
||||
assert.deepStrictEqual(editor.getSelections()!.map(fromRange), [
|
||||
[2, 9, 2, 16],
|
||||
[1, 9, 1, 16],
|
||||
[3, 9, 3, 16],
|
||||
@@ -98,7 +98,7 @@ suite('Multicursor selection', () => {
|
||||
|
||||
editor.trigger('test', 'removeSecondaryCursors', null);
|
||||
|
||||
assert.deepEqual(fromRange(editor.getSelection()!), [2, 9, 2, 16]);
|
||||
assert.deepStrictEqual(fromRange(editor.getSelection()!), [2, 9, 2, 16]);
|
||||
|
||||
multiCursorSelectController.dispose();
|
||||
findController.dispose();
|
||||
@@ -121,13 +121,13 @@ suite('Multicursor selection', () => {
|
||||
findController.getState().change({ searchString: 'some+thing', isRegex: true, isRevealed: true }, false);
|
||||
|
||||
selectHighlightsAction.run(null!, editor);
|
||||
assert.deepEqual(editor.getSelections()!.map(fromRange), [
|
||||
assert.deepStrictEqual(editor.getSelections()!.map(fromRange), [
|
||||
[1, 1, 1, 10],
|
||||
[2, 1, 2, 11],
|
||||
[3, 1, 3, 12],
|
||||
]);
|
||||
|
||||
assert.equal(findController.getState().searchString, 'some+thing');
|
||||
assert.strictEqual(findController.getState().searchString, 'some+thing');
|
||||
|
||||
multiCursorSelectController.dispose();
|
||||
findController.dispose();
|
||||
@@ -154,14 +154,14 @@ suite('Multicursor selection', () => {
|
||||
editor.setSelection(new Selection(2, 1, 3, 4));
|
||||
|
||||
addSelectionToNextFindMatch.run(null!, editor);
|
||||
assert.deepEqual(editor.getSelections()!.map(fromRange), [
|
||||
assert.deepStrictEqual(editor.getSelections()!.map(fromRange), [
|
||||
[2, 1, 3, 4],
|
||||
[8, 1, 9, 4]
|
||||
]);
|
||||
|
||||
editor.trigger('test', 'removeSecondaryCursors', null);
|
||||
|
||||
assert.deepEqual(fromRange(editor.getSelection()!), [2, 1, 3, 4]);
|
||||
assert.deepStrictEqual(fromRange(editor.getSelection()!), [2, 1, 3, 4]);
|
||||
|
||||
multiCursorSelectController.dispose();
|
||||
findController.dispose();
|
||||
@@ -182,7 +182,7 @@ suite('Multicursor selection', () => {
|
||||
editor.setSelection(new Selection(1, 1, 1, 4));
|
||||
|
||||
addSelectionToNextFindMatch.run(null!, editor);
|
||||
assert.deepEqual(editor.getSelections()!.map(fromRange), [
|
||||
assert.deepStrictEqual(editor.getSelections()!.map(fromRange), [
|
||||
[1, 1, 1, 4],
|
||||
[1, 4, 1, 7]
|
||||
]);
|
||||
@@ -190,7 +190,7 @@ suite('Multicursor selection', () => {
|
||||
addSelectionToNextFindMatch.run(null!, editor);
|
||||
addSelectionToNextFindMatch.run(null!, editor);
|
||||
addSelectionToNextFindMatch.run(null!, editor);
|
||||
assert.deepEqual(editor.getSelections()!.map(fromRange), [
|
||||
assert.deepStrictEqual(editor.getSelections()!.map(fromRange), [
|
||||
[1, 1, 1, 4],
|
||||
[1, 4, 1, 7],
|
||||
[2, 1, 2, 4],
|
||||
@@ -199,14 +199,14 @@ suite('Multicursor selection', () => {
|
||||
]);
|
||||
|
||||
editor.trigger('test', Handler.Type, { text: 'z' });
|
||||
assert.deepEqual(editor.getSelections()!.map(fromRange), [
|
||||
assert.deepStrictEqual(editor.getSelections()!.map(fromRange), [
|
||||
[1, 2, 1, 2],
|
||||
[1, 3, 1, 3],
|
||||
[2, 2, 2, 2],
|
||||
[3, 2, 3, 2],
|
||||
[3, 3, 3, 3]
|
||||
]);
|
||||
assert.equal(editor.getValue(), [
|
||||
assert.strictEqual(editor.getValue(), [
|
||||
'zz',
|
||||
'z',
|
||||
'zz',
|
||||
@@ -239,14 +239,14 @@ suite('Multicursor selection', () => {
|
||||
editor.setSelection(new Selection(2, 1, 3, 4));
|
||||
|
||||
addSelectionToNextFindMatch.run(null!, editor);
|
||||
assert.deepEqual(editor.getSelections()!.map(fromRange), [
|
||||
assert.deepStrictEqual(editor.getSelections()!.map(fromRange), [
|
||||
[2, 1, 3, 4],
|
||||
[8, 1, 9, 4]
|
||||
]);
|
||||
|
||||
editor.trigger('test', 'removeSecondaryCursors', null);
|
||||
|
||||
assert.deepEqual(fromRange(editor.getSelection()!), [2, 1, 3, 4]);
|
||||
assert.deepStrictEqual(fromRange(editor.getSelection()!), [2, 1, 3, 4]);
|
||||
|
||||
multiCursorSelectController.dispose();
|
||||
findController.dispose();
|
||||
@@ -284,25 +284,25 @@ suite('Multicursor selection', () => {
|
||||
]);
|
||||
|
||||
action.run(null!, editor);
|
||||
assert.deepEqual(editor.getSelections(), [
|
||||
assert.deepStrictEqual(editor.getSelections(), [
|
||||
new Selection(1, 1, 1, 4),
|
||||
]);
|
||||
|
||||
action.run(null!, editor);
|
||||
assert.deepEqual(editor.getSelections(), [
|
||||
assert.deepStrictEqual(editor.getSelections(), [
|
||||
new Selection(1, 1, 1, 4),
|
||||
new Selection(2, 1, 2, 4),
|
||||
]);
|
||||
|
||||
action.run(null!, editor);
|
||||
assert.deepEqual(editor.getSelections(), [
|
||||
assert.deepStrictEqual(editor.getSelections(), [
|
||||
new Selection(1, 1, 1, 4),
|
||||
new Selection(2, 1, 2, 4),
|
||||
new Selection(3, 1, 3, 4),
|
||||
]);
|
||||
|
||||
action.run(null!, editor);
|
||||
assert.deepEqual(editor.getSelections(), [
|
||||
assert.deepStrictEqual(editor.getSelections(), [
|
||||
new Selection(1, 1, 1, 4),
|
||||
new Selection(2, 1, 2, 4),
|
||||
new Selection(3, 1, 3, 4),
|
||||
@@ -323,20 +323,20 @@ suite('Multicursor selection', () => {
|
||||
]);
|
||||
|
||||
action.run(null!, editor);
|
||||
assert.deepEqual(editor.getSelections(), [
|
||||
assert.deepStrictEqual(editor.getSelections(), [
|
||||
new Selection(1, 1, 1, 4),
|
||||
new Selection(2, 1, 2, 4),
|
||||
]);
|
||||
|
||||
action.run(null!, editor);
|
||||
assert.deepEqual(editor.getSelections(), [
|
||||
assert.deepStrictEqual(editor.getSelections(), [
|
||||
new Selection(1, 1, 1, 4),
|
||||
new Selection(2, 1, 2, 4),
|
||||
new Selection(3, 1, 3, 4),
|
||||
]);
|
||||
|
||||
action.run(null!, editor);
|
||||
assert.deepEqual(editor.getSelections(), [
|
||||
assert.deepStrictEqual(editor.getSelections(), [
|
||||
new Selection(1, 1, 1, 4),
|
||||
new Selection(2, 1, 2, 4),
|
||||
new Selection(3, 1, 3, 4),
|
||||
@@ -357,20 +357,20 @@ suite('Multicursor selection', () => {
|
||||
]);
|
||||
|
||||
action.run(null!, editor);
|
||||
assert.deepEqual(editor.getSelections(), [
|
||||
assert.deepStrictEqual(editor.getSelections(), [
|
||||
new Selection(1, 1, 1, 4),
|
||||
new Selection(2, 1, 2, 4),
|
||||
]);
|
||||
|
||||
action.run(null!, editor);
|
||||
assert.deepEqual(editor.getSelections(), [
|
||||
assert.deepStrictEqual(editor.getSelections(), [
|
||||
new Selection(1, 1, 1, 4),
|
||||
new Selection(2, 1, 2, 4),
|
||||
new Selection(3, 1, 3, 4),
|
||||
]);
|
||||
|
||||
action.run(null!, editor);
|
||||
assert.deepEqual(editor.getSelections(), [
|
||||
assert.deepStrictEqual(editor.getSelections(), [
|
||||
new Selection(1, 1, 1, 4),
|
||||
new Selection(2, 1, 2, 4),
|
||||
new Selection(3, 1, 3, 4),
|
||||
@@ -392,14 +392,14 @@ suite('Multicursor selection', () => {
|
||||
]);
|
||||
|
||||
action.run(null!, editor);
|
||||
assert.deepEqual(editor.getSelections(), [
|
||||
assert.deepStrictEqual(editor.getSelections(), [
|
||||
new Selection(1, 1, 1, 4),
|
||||
new Selection(2, 1, 2, 4),
|
||||
new Selection(3, 1, 3, 4),
|
||||
]);
|
||||
|
||||
action.run(null!, editor);
|
||||
assert.deepEqual(editor.getSelections(), [
|
||||
assert.deepStrictEqual(editor.getSelections(), [
|
||||
new Selection(1, 1, 1, 4),
|
||||
new Selection(2, 1, 2, 4),
|
||||
new Selection(3, 1, 3, 4),
|
||||
@@ -421,14 +421,14 @@ suite('Multicursor selection', () => {
|
||||
]);
|
||||
|
||||
action.run(null!, editor);
|
||||
assert.deepEqual(editor.getSelections(), [
|
||||
assert.deepStrictEqual(editor.getSelections(), [
|
||||
new Selection(1, 5, 1, 10),
|
||||
new Selection(2, 5, 2, 10),
|
||||
new Selection(3, 5, 3, 8),
|
||||
]);
|
||||
|
||||
action.run(null!, editor);
|
||||
assert.deepEqual(editor.getSelections(), [
|
||||
assert.deepStrictEqual(editor.getSelections(), [
|
||||
new Selection(1, 5, 1, 10),
|
||||
new Selection(2, 5, 2, 10),
|
||||
new Selection(3, 5, 3, 8),
|
||||
@@ -450,20 +450,20 @@ suite('Multicursor selection', () => {
|
||||
]);
|
||||
|
||||
action.run(null!, editor);
|
||||
assert.deepEqual(editor.getSelections(), [
|
||||
assert.deepStrictEqual(editor.getSelections(), [
|
||||
new Selection(1, 1, 1, 5),
|
||||
new Selection(2, 1, 2, 5),
|
||||
]);
|
||||
|
||||
action.run(null!, editor);
|
||||
assert.deepEqual(editor.getSelections(), [
|
||||
assert.deepStrictEqual(editor.getSelections(), [
|
||||
new Selection(1, 1, 1, 5),
|
||||
new Selection(2, 1, 2, 5),
|
||||
new Selection(3, 1, 3, 5),
|
||||
]);
|
||||
|
||||
action.run(null!, editor);
|
||||
assert.deepEqual(editor.getSelections(), [
|
||||
assert.deepStrictEqual(editor.getSelections(), [
|
||||
new Selection(1, 1, 1, 5),
|
||||
new Selection(2, 1, 2, 5),
|
||||
new Selection(3, 1, 3, 5),
|
||||
@@ -471,7 +471,7 @@ suite('Multicursor selection', () => {
|
||||
]);
|
||||
|
||||
action.run(null!, editor);
|
||||
assert.deepEqual(editor.getSelections(), [
|
||||
assert.deepStrictEqual(editor.getSelections(), [
|
||||
new Selection(1, 1, 1, 5),
|
||||
new Selection(2, 1, 2, 5),
|
||||
new Selection(3, 1, 3, 5),
|
||||
@@ -480,7 +480,7 @@ suite('Multicursor selection', () => {
|
||||
]);
|
||||
|
||||
action.run(null!, editor);
|
||||
assert.deepEqual(editor.getSelections(), [
|
||||
assert.deepStrictEqual(editor.getSelections(), [
|
||||
new Selection(1, 1, 1, 5),
|
||||
new Selection(2, 1, 2, 5),
|
||||
new Selection(3, 1, 3, 5),
|
||||
@@ -508,18 +508,18 @@ suite('Multicursor selection', () => {
|
||||
]);
|
||||
|
||||
action.run(null!, editor);
|
||||
assert.deepEqual(editor.getSelections(), [
|
||||
assert.deepStrictEqual(editor.getSelections(), [
|
||||
new Selection(1, 1, 1, 4),
|
||||
]);
|
||||
|
||||
action.run(null!, editor);
|
||||
assert.deepEqual(editor.getSelections(), [
|
||||
assert.deepStrictEqual(editor.getSelections(), [
|
||||
new Selection(1, 1, 1, 4),
|
||||
new Selection(4, 1, 4, 4),
|
||||
]);
|
||||
|
||||
action.run(null!, editor);
|
||||
assert.deepEqual(editor.getSelections(), [
|
||||
assert.deepStrictEqual(editor.getSelections(), [
|
||||
new Selection(1, 1, 1, 4),
|
||||
new Selection(4, 1, 4, 4),
|
||||
new Selection(6, 2, 6, 5),
|
||||
@@ -534,12 +534,12 @@ suite('Multicursor selection', () => {
|
||||
]);
|
||||
|
||||
action.run(null!, editor);
|
||||
assert.deepEqual(editor.getSelections(), [
|
||||
assert.deepStrictEqual(editor.getSelections(), [
|
||||
new Selection(1, 1, 1, 4),
|
||||
]);
|
||||
|
||||
action.run(null!, editor);
|
||||
assert.deepEqual(editor.getSelections(), [
|
||||
assert.deepStrictEqual(editor.getSelections(), [
|
||||
new Selection(1, 1, 1, 4),
|
||||
new Selection(4, 1, 4, 4),
|
||||
]);
|
||||
@@ -550,7 +550,7 @@ suite('Multicursor selection', () => {
|
||||
]);
|
||||
|
||||
action.run(null!, editor);
|
||||
assert.deepEqual(editor.getSelections(), [
|
||||
assert.deepStrictEqual(editor.getSelections(), [
|
||||
new Selection(1, 1, 1, 4),
|
||||
new Selection(2, 1, 2, 4),
|
||||
]);
|
||||
@@ -565,14 +565,14 @@ suite('Multicursor selection', () => {
|
||||
]);
|
||||
|
||||
action.run(null!, editor);
|
||||
assert.deepEqual(editor.getSelections(), [
|
||||
assert.deepStrictEqual(editor.getSelections(), [
|
||||
new Selection(1, 1, 1, 4),
|
||||
new Selection(4, 1, 4, 4),
|
||||
new Selection(6, 2, 6, 5),
|
||||
]);
|
||||
|
||||
action.run(null!, editor);
|
||||
assert.deepEqual(editor.getSelections(), [
|
||||
assert.deepStrictEqual(editor.getSelections(), [
|
||||
new Selection(1, 1, 1, 4),
|
||||
new Selection(4, 1, 4, 4),
|
||||
new Selection(6, 2, 6, 5),
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
line-height: 1.5em;
|
||||
}
|
||||
|
||||
.monaco-editor .parameter-hints-widget > .wrapper {
|
||||
.monaco-editor .parameter-hints-widget > .phwrapper {
|
||||
max-width: 440px;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
|
||||
@@ -14,7 +14,7 @@ import { ContentWidgetPositionPreference, ICodeEditor, IContentWidget, IContentW
|
||||
import { ConfigurationChangedEvent, EditorOption } from 'vs/editor/common/config/editorOptions';
|
||||
import * as modes from 'vs/editor/common/modes';
|
||||
import { IModeService } from 'vs/editor/common/services/modeService';
|
||||
import { MarkdownRenderer } from 'vs/editor/browser/core/markdownRenderer';
|
||||
import { IMarkdownRenderResult, MarkdownRenderer } from 'vs/editor/browser/core/markdownRenderer';
|
||||
import { Context } from 'vs/editor/contrib/parameterHints/provideSignatureHelp';
|
||||
import * as nls from 'vs/nls';
|
||||
import { IContextKey, IContextKeyService } from 'vs/platform/contextkey/common/contextkey';
|
||||
@@ -27,6 +27,7 @@ import { Codicon } from 'vs/base/common/codicons';
|
||||
import { assertIsDefined } from 'vs/base/common/types';
|
||||
import { ColorScheme } from 'vs/platform/theme/common/theme';
|
||||
import { registerIcon } from 'vs/platform/theme/common/iconRegistry';
|
||||
import { IMarkdownString } from 'vs/base/common/htmlContent';
|
||||
|
||||
const $ = dom.$;
|
||||
|
||||
@@ -81,7 +82,7 @@ export class ParameterHintsWidget extends Disposable implements IContentWidget {
|
||||
|
||||
private createParamaterHintDOMNodes() {
|
||||
const element = $('.editor-widget.parameter-hints-widget');
|
||||
const wrapper = dom.append(element, $('.wrapper'));
|
||||
const wrapper = dom.append(element, $('.phwrapper'));
|
||||
wrapper.tabIndex = -1;
|
||||
|
||||
const controls = dom.append(wrapper, $('.controls'));
|
||||
@@ -225,8 +226,7 @@ export class ParameterHintsWidget extends Disposable implements IContentWidget {
|
||||
if (typeof activeParameter.documentation === 'string') {
|
||||
documentation.textContent = activeParameter.documentation;
|
||||
} else {
|
||||
const renderedContents = this.renderDisposeables.add(this.markdownRenderer.render(activeParameter.documentation));
|
||||
renderedContents.element.classList.add('markdown-docs');
|
||||
const renderedContents = this.renderMarkdownDocs(activeParameter.documentation);
|
||||
documentation.appendChild(renderedContents.element);
|
||||
}
|
||||
dom.append(this.domNodes.docs, $('p', {}, documentation));
|
||||
@@ -237,8 +237,7 @@ export class ParameterHintsWidget extends Disposable implements IContentWidget {
|
||||
} else if (typeof signature.documentation === 'string') {
|
||||
dom.append(this.domNodes.docs, $('p', {}, signature.documentation));
|
||||
} else {
|
||||
const renderedContents = this.renderDisposeables.add(this.markdownRenderer.render(signature.documentation));
|
||||
renderedContents.element.classList.add('markdown-docs');
|
||||
const renderedContents = this.renderMarkdownDocs(signature.documentation);
|
||||
dom.append(this.domNodes.docs, renderedContents.element);
|
||||
}
|
||||
|
||||
@@ -265,6 +264,16 @@ export class ParameterHintsWidget extends Disposable implements IContentWidget {
|
||||
this.domNodes.scrollbar.scanDomNode();
|
||||
}
|
||||
|
||||
private renderMarkdownDocs(markdown: IMarkdownString | undefined): IMarkdownRenderResult {
|
||||
const renderedContents = this.renderDisposeables.add(this.markdownRenderer.render(markdown, {
|
||||
asyncRenderCallback: () => {
|
||||
this.domNodes?.scrollbar.scanDomNode();
|
||||
}
|
||||
}));
|
||||
renderedContents.element.classList.add('markdown-docs');
|
||||
return renderedContents;
|
||||
}
|
||||
|
||||
private hasDocs(signature: modes.SignatureInformation, activeParameter: modes.ParameterInformation | undefined): boolean {
|
||||
if (activeParameter && typeof activeParameter.documentation === 'string' && assertIsDefined(activeParameter.documentation).length > 0) {
|
||||
return true;
|
||||
@@ -360,7 +369,7 @@ export class ParameterHintsWidget extends Disposable implements IContentWidget {
|
||||
const height = Math.max(this.editor.getLayoutInfo().height / 4, 250);
|
||||
const maxHeight = `${height}px`;
|
||||
this.domNodes.element.style.maxHeight = maxHeight;
|
||||
const wrapper = this.domNodes.element.getElementsByClassName('wrapper') as HTMLCollectionOf<HTMLElement>;
|
||||
const wrapper = this.domNodes.element.getElementsByClassName('phwrapper') as HTMLCollectionOf<HTMLElement>;
|
||||
if (wrapper.length) {
|
||||
wrapper[0].style.maxHeight = maxHeight;
|
||||
}
|
||||
|
||||
@@ -3,7 +3,6 @@
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { first } from 'vs/base/common/async';
|
||||
import { onUnexpectedExternalError } from 'vs/base/common/errors';
|
||||
import { IPosition, Position } from 'vs/editor/common/core/position';
|
||||
import { ITextModel } from 'vs/editor/common/model';
|
||||
@@ -20,19 +19,26 @@ export const Context = {
|
||||
MultipleSignatures: new RawContextKey<boolean>('parameterHintsMultipleSignatures', false),
|
||||
};
|
||||
|
||||
export function provideSignatureHelp(
|
||||
export async function provideSignatureHelp(
|
||||
model: ITextModel,
|
||||
position: Position,
|
||||
context: modes.SignatureHelpContext,
|
||||
token: CancellationToken
|
||||
): Promise<modes.SignatureHelpResult | null | undefined> {
|
||||
): Promise<modes.SignatureHelpResult | undefined> {
|
||||
|
||||
const supports = modes.SignatureHelpProviderRegistry.ordered(model);
|
||||
|
||||
return first(supports.map(support => () => {
|
||||
return Promise.resolve(support.provideSignatureHelp(model, position, token, context))
|
||||
.catch<modes.SignatureHelpResult | undefined>(e => onUnexpectedExternalError(e));
|
||||
}));
|
||||
for (const support of supports) {
|
||||
try {
|
||||
const result = await support.provideSignatureHelp(model, position, token, context);
|
||||
if (result) {
|
||||
return result;
|
||||
}
|
||||
} catch (err) {
|
||||
onUnexpectedExternalError(err);
|
||||
}
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
|
||||
CommandsRegistry.registerCommand('_executeSignatureHelpProvider', async (accessor, ...args: [URI, IPosition, string?]) => {
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
import 'vs/css!./media/peekViewWidget';
|
||||
import * as dom from 'vs/base/browser/dom';
|
||||
import { IMouseEvent } from 'vs/base/browser/mouseEvent';
|
||||
import { ActionBar, IActionBarOptions } from 'vs/base/browser/ui/actionbar/actionbar';
|
||||
import { ActionBar, ActionsOrientation, IActionBarOptions } from 'vs/base/browser/ui/actionbar/actionbar';
|
||||
import { Action } from 'vs/base/common/actions';
|
||||
import { Color } from 'vs/base/common/color';
|
||||
import { Emitter } from 'vs/base/common/event';
|
||||
@@ -25,8 +25,7 @@ import { registerEditorContribution } from 'vs/editor/browser/editorExtensions';
|
||||
import { IEditorContribution } from 'vs/editor/common/editorCommon';
|
||||
import { registerColor, contrastBorder, activeContrastBorder } from 'vs/platform/theme/common/colorRegistry';
|
||||
import { Codicon } from 'vs/base/common/codicons';
|
||||
import { MenuItemAction, SubmenuItemAction } from 'vs/platform/actions/common/actions';
|
||||
import { MenuEntryActionViewItem, SubmenuEntryActionViewItem } from 'vs/platform/actions/browser/menuEntryActionViewItem';
|
||||
import { createActionViewItem } from 'vs/platform/actions/browser/menuEntryActionViewItem';
|
||||
|
||||
export const IPeekViewService = createDecorator<IPeekViewService>('IPeekViewService');
|
||||
export interface IPeekViewService {
|
||||
@@ -107,6 +106,7 @@ export abstract class PeekViewWidget extends ZoneWidget {
|
||||
|
||||
private readonly _onDidClose = new Emitter<PeekViewWidget>();
|
||||
readonly onDidClose = this._onDidClose.event;
|
||||
private disposed?: true;
|
||||
|
||||
protected _headElement?: HTMLDivElement;
|
||||
protected _primaryHeading?: HTMLElement;
|
||||
@@ -125,8 +125,11 @@ export abstract class PeekViewWidget extends ZoneWidget {
|
||||
}
|
||||
|
||||
dispose(): void {
|
||||
super.dispose();
|
||||
this._onDidClose.fire(this);
|
||||
if (!this.disposed) {
|
||||
this.disposed = true; // prevent consumers who dispose on onDidClose from looping
|
||||
super.dispose();
|
||||
this._onDidClose.fire(this);
|
||||
}
|
||||
}
|
||||
|
||||
style(styles: IPeekViewStyles): void {
|
||||
@@ -204,15 +207,8 @@ export abstract class PeekViewWidget extends ZoneWidget {
|
||||
|
||||
protected _getActionBarOptions(): IActionBarOptions {
|
||||
return {
|
||||
actionViewItemProvider: action => {
|
||||
if (action instanceof MenuItemAction) {
|
||||
return this.instantiationService.createInstance(MenuEntryActionViewItem, action);
|
||||
} else if (action instanceof SubmenuItemAction) {
|
||||
return this.instantiationService.createInstance(SubmenuEntryActionViewItem, action);
|
||||
}
|
||||
|
||||
return undefined;
|
||||
}
|
||||
actionViewItemProvider: createActionViewItem.bind(undefined, this.instantiationService),
|
||||
orientation: ActionsOrientation.HORIZONTAL
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -10,7 +10,7 @@ import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding';
|
||||
import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
|
||||
import { INotificationService } from 'vs/platform/notification/common/notification';
|
||||
import { ICommandService } from 'vs/platform/commands/common/commands';
|
||||
import { stripCodicons } from 'vs/base/common/codicons';
|
||||
import { stripIcons } from 'vs/base/common/iconLabels';
|
||||
|
||||
export abstract class AbstractEditorCommandsQuickAccessProvider extends AbstractCommandsQuickAccessProvider {
|
||||
|
||||
@@ -41,7 +41,7 @@ export abstract class AbstractEditorCommandsQuickAccessProvider extends Abstract
|
||||
editorCommandPicks.push({
|
||||
commandId: editorAction.id,
|
||||
commandAlias: editorAction.alias,
|
||||
label: stripCodicons(editorAction.label) || editorAction.id,
|
||||
label: stripIcons(editorAction.label) || editorAction.id,
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -12,11 +12,10 @@ import { ITextModel } from 'vs/editor/common/model';
|
||||
import { IRange, Range } from 'vs/editor/common/core/range';
|
||||
import { AbstractEditorNavigationQuickAccessProvider, IEditorNavigationQuickAccessOptions, IQuickAccessTextEditorContext } from 'vs/editor/contrib/quickAccess/editorNavigationQuickAccess';
|
||||
import { DocumentSymbol, SymbolKinds, SymbolTag, DocumentSymbolProviderRegistry, SymbolKind } from 'vs/editor/common/modes';
|
||||
import { OutlineModel, OutlineElement } from 'vs/editor/contrib/documentSymbols/outlineModel';
|
||||
import { OutlineModel } from 'vs/editor/contrib/documentSymbols/outlineModel';
|
||||
import { trim, format } from 'vs/base/common/strings';
|
||||
import { prepareQuery, IPreparedQuery, pieceToQuery, scoreFuzzy2 } from 'vs/base/common/fuzzyScorer';
|
||||
import { IMatch } from 'vs/base/common/filters';
|
||||
import { Iterable } from 'vs/base/common/iterator';
|
||||
import { Codicon } from 'vs/base/common/codicons';
|
||||
|
||||
export interface IGotoSymbolQuickPickItem extends IQuickPickItem {
|
||||
@@ -144,7 +143,7 @@ export abstract class AbstractGotoSymbolQuickAccessProvider extends AbstractEdit
|
||||
|
||||
// Resolve symbols from document once and reuse this
|
||||
// request for all filtering and typing then on
|
||||
const symbolsPromise = this.getDocumentSymbols(model, true, token);
|
||||
const symbolsPromise = this.getDocumentSymbols(model, token);
|
||||
|
||||
// Set initial picks and update on type
|
||||
let picksCts: CancellationTokenSource | undefined = undefined;
|
||||
@@ -418,49 +417,9 @@ export abstract class AbstractGotoSymbolQuickAccessProvider extends AbstractEdit
|
||||
return result;
|
||||
}
|
||||
|
||||
protected async getDocumentSymbols(document: ITextModel, flatten: boolean, token: CancellationToken): Promise<DocumentSymbol[]> {
|
||||
protected async getDocumentSymbols(document: ITextModel, token: CancellationToken): Promise<DocumentSymbol[]> {
|
||||
const model = await OutlineModel.create(document, token);
|
||||
if (token.isCancellationRequested) {
|
||||
return [];
|
||||
}
|
||||
|
||||
const roots: DocumentSymbol[] = [];
|
||||
for (const child of model.children.values()) {
|
||||
if (child instanceof OutlineElement) {
|
||||
roots.push(child.symbol);
|
||||
} else {
|
||||
roots.push(...Iterable.map(child.children.values(), child => child.symbol));
|
||||
}
|
||||
}
|
||||
|
||||
let flatEntries: DocumentSymbol[] = [];
|
||||
if (flatten) {
|
||||
this.flattenDocumentSymbols(flatEntries, roots, '');
|
||||
} else {
|
||||
flatEntries = roots;
|
||||
}
|
||||
|
||||
return flatEntries.sort((symbolA, symbolB) => Range.compareRangesUsingStarts(symbolA.range, symbolB.range));
|
||||
}
|
||||
|
||||
private flattenDocumentSymbols(bucket: DocumentSymbol[], entries: DocumentSymbol[], overrideContainerLabel: string): void {
|
||||
for (const entry of entries) {
|
||||
bucket.push({
|
||||
kind: entry.kind,
|
||||
tags: entry.tags,
|
||||
name: entry.name,
|
||||
detail: entry.detail,
|
||||
containerName: entry.containerName || overrideContainerLabel,
|
||||
range: entry.range,
|
||||
selectionRange: entry.selectionRange,
|
||||
children: undefined, // we flatten it...
|
||||
});
|
||||
|
||||
// Recurse over children
|
||||
if (entry.children) {
|
||||
this.flattenDocumentSymbols(bucket, entry.children, entry.name);
|
||||
}
|
||||
}
|
||||
return token.isCancellationRequested ? [] : model.asListOfDocumentSymbols();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -26,7 +26,7 @@ export class BracketSelectionRangeProvider implements SelectionRangeProvider {
|
||||
return result;
|
||||
}
|
||||
|
||||
private static readonly _maxDuration = 30;
|
||||
public static _maxDuration = 30;
|
||||
private static readonly _maxRounds = 2;
|
||||
|
||||
private static _bracketsRightYield(resolve: () => void, round: number, model: ITextModel, pos: Position, ranges: Map<string, LinkedList<Range>>): void {
|
||||
|
||||
@@ -16,7 +16,7 @@ import { BracketSelectionRangeProvider } from 'vs/editor/contrib/smartSelect/bra
|
||||
import { provideSelectionRanges } from 'vs/editor/contrib/smartSelect/smartSelect';
|
||||
import { CancellationToken } from 'vs/base/common/cancellation';
|
||||
import { WordSelectionRangeProvider } from 'vs/editor/contrib/smartSelect/wordSelections';
|
||||
import { TestTextResourcePropertiesService } from 'vs/editor/test/common/services/modelService.test';
|
||||
import { TestTextResourcePropertiesService } from 'vs/editor/test/common/services/testTextResourcePropertiesService';
|
||||
import { TestThemeService } from 'vs/platform/theme/test/common/testThemeService';
|
||||
import { NullLogService } from 'vs/platform/log/common/log';
|
||||
import { UndoRedoService } from 'vs/platform/undoRedo/common/undoRedoService';
|
||||
@@ -45,6 +45,16 @@ class MockJSMode extends MockMode {
|
||||
|
||||
suite('SmartSelect', () => {
|
||||
|
||||
const OriginalBracketSelectionRangeProviderMaxDuration = BracketSelectionRangeProvider._maxDuration;
|
||||
|
||||
suiteSetup(() => {
|
||||
BracketSelectionRangeProvider._maxDuration = 5000; // 5 seconds
|
||||
});
|
||||
|
||||
suiteTeardown(() => {
|
||||
BracketSelectionRangeProvider._maxDuration = OriginalBracketSelectionRangeProviderMaxDuration;
|
||||
});
|
||||
|
||||
let modelService: ModelServiceImpl;
|
||||
let mode: MockJSMode;
|
||||
|
||||
|
||||
@@ -12,11 +12,11 @@ import { VariableResolver, Variable, Text } from 'vs/editor/contrib/snippet/snip
|
||||
import { LanguageConfigurationRegistry } from 'vs/editor/common/modes/languageConfigurationRegistry';
|
||||
import { getLeadingWhitespace, commonPrefixLength, isFalsyOrWhitespace, splitLines } from 'vs/base/common/strings';
|
||||
import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace';
|
||||
import { isSingleFolderWorkspaceIdentifier, toWorkspaceIdentifier, WORKSPACE_EXTENSION, IWorkspaceIdentifier } from 'vs/platform/workspaces/common/workspaces';
|
||||
import { toWorkspaceIdentifier, WORKSPACE_EXTENSION, IWorkspaceIdentifier, ISingleFolderWorkspaceIdentifier, isSingleFolderWorkspaceIdentifier } from 'vs/platform/workspaces/common/workspaces';
|
||||
import { ILabelService } from 'vs/platform/label/common/label';
|
||||
import { normalizeDriveLetter } from 'vs/base/common/labels';
|
||||
import { URI } from 'vs/base/common/uri';
|
||||
import { OvertypingCapturer } from 'vs/editor/contrib/suggest/suggestOvertypingCapturer';
|
||||
import { generateUuid } from 'vs/base/common/uuid';
|
||||
|
||||
export const KnownSnippetVariableNames: { [key: string]: true } = Object.freeze({
|
||||
'CURRENT_YEAR': true,
|
||||
@@ -42,6 +42,7 @@ export const KnownSnippetVariableNames: { [key: string]: true } = Object.freeze(
|
||||
'TM_FILENAME_BASE': true,
|
||||
'TM_DIRECTORY': true,
|
||||
'TM_FILEPATH': true,
|
||||
'RELATIVE_FILEPATH': true,
|
||||
'BLOCK_COMMENT_START': true,
|
||||
'BLOCK_COMMENT_END': true,
|
||||
'LINE_COMMENT': true,
|
||||
@@ -49,6 +50,7 @@ export const KnownSnippetVariableNames: { [key: string]: true } = Object.freeze(
|
||||
'WORKSPACE_FOLDER': true,
|
||||
'RANDOM': true,
|
||||
'RANDOM_HEX': true,
|
||||
'UUID': true
|
||||
});
|
||||
|
||||
export class CompositeSnippetVariableResolver implements VariableResolver {
|
||||
@@ -177,6 +179,8 @@ export class ModelBasedVariableResolver implements VariableResolver {
|
||||
|
||||
} else if (name === 'TM_FILEPATH' && this._labelService) {
|
||||
return this._labelService.getUriLabel(this._model.uri);
|
||||
} else if (name === 'RELATIVE_FILEPATH' && this._labelService) {
|
||||
return this._labelService.getUriLabel(this._model.uri, { relative: true, noPrefix: true });
|
||||
}
|
||||
|
||||
return undefined;
|
||||
@@ -309,9 +313,9 @@ export class WorkspaceBasedVariableResolver implements VariableResolver {
|
||||
|
||||
return undefined;
|
||||
}
|
||||
private _resolveWorkspaceName(workspaceIdentifier: IWorkspaceIdentifier | URI): string | undefined {
|
||||
private _resolveWorkspaceName(workspaceIdentifier: IWorkspaceIdentifier | ISingleFolderWorkspaceIdentifier): string | undefined {
|
||||
if (isSingleFolderWorkspaceIdentifier(workspaceIdentifier)) {
|
||||
return path.basename(workspaceIdentifier.path);
|
||||
return path.basename(workspaceIdentifier.uri.path);
|
||||
}
|
||||
|
||||
let filename = path.basename(workspaceIdentifier.configPath.path);
|
||||
@@ -320,9 +324,9 @@ export class WorkspaceBasedVariableResolver implements VariableResolver {
|
||||
}
|
||||
return filename;
|
||||
}
|
||||
private _resoveWorkspacePath(workspaceIdentifier: IWorkspaceIdentifier | URI): string | undefined {
|
||||
private _resoveWorkspacePath(workspaceIdentifier: IWorkspaceIdentifier | ISingleFolderWorkspaceIdentifier): string | undefined {
|
||||
if (isSingleFolderWorkspaceIdentifier(workspaceIdentifier)) {
|
||||
return normalizeDriveLetter(workspaceIdentifier.fsPath);
|
||||
return normalizeDriveLetter(workspaceIdentifier.uri.fsPath);
|
||||
}
|
||||
|
||||
let filename = path.basename(workspaceIdentifier.configPath.path);
|
||||
@@ -340,9 +344,10 @@ export class RandomBasedVariableResolver implements VariableResolver {
|
||||
|
||||
if (name === 'RANDOM') {
|
||||
return Math.random().toString().slice(-6);
|
||||
}
|
||||
else if (name === 'RANDOM_HEX') {
|
||||
} else if (name === 'RANDOM_HEX') {
|
||||
return Math.random().toString(16).slice(-6);
|
||||
} else if (name === 'UUID') {
|
||||
return generateUuid();
|
||||
}
|
||||
|
||||
return undefined;
|
||||
|
||||
@@ -62,34 +62,34 @@ suite('SnippetController', () => {
|
||||
editor.setPosition({ lineNumber: 4, column: 2 });
|
||||
|
||||
snippetController.insert(template);
|
||||
assert.equal(editor.getModel()!.getLineContent(4), '\tfor (var index; index < array.length; index++) {');
|
||||
assert.equal(editor.getModel()!.getLineContent(5), '\t\tvar element = array[index];');
|
||||
assert.equal(editor.getModel()!.getLineContent(6), '\t\t');
|
||||
assert.equal(editor.getModel()!.getLineContent(7), '\t}');
|
||||
assert.strictEqual(editor.getModel()!.getLineContent(4), '\tfor (var index; index < array.length; index++) {');
|
||||
assert.strictEqual(editor.getModel()!.getLineContent(5), '\t\tvar element = array[index];');
|
||||
assert.strictEqual(editor.getModel()!.getLineContent(6), '\t\t');
|
||||
assert.strictEqual(editor.getModel()!.getLineContent(7), '\t}');
|
||||
|
||||
editor.trigger('test', 'type', { text: 'i' });
|
||||
assert.equal(editor.getModel()!.getLineContent(4), '\tfor (var i; i < array.length; i++) {');
|
||||
assert.equal(editor.getModel()!.getLineContent(5), '\t\tvar element = array[i];');
|
||||
assert.equal(editor.getModel()!.getLineContent(6), '\t\t');
|
||||
assert.equal(editor.getModel()!.getLineContent(7), '\t}');
|
||||
assert.strictEqual(editor.getModel()!.getLineContent(4), '\tfor (var i; i < array.length; i++) {');
|
||||
assert.strictEqual(editor.getModel()!.getLineContent(5), '\t\tvar element = array[i];');
|
||||
assert.strictEqual(editor.getModel()!.getLineContent(6), '\t\t');
|
||||
assert.strictEqual(editor.getModel()!.getLineContent(7), '\t}');
|
||||
|
||||
snippetController.next();
|
||||
editor.trigger('test', 'type', { text: 'arr' });
|
||||
assert.equal(editor.getModel()!.getLineContent(4), '\tfor (var i; i < arr.length; i++) {');
|
||||
assert.equal(editor.getModel()!.getLineContent(5), '\t\tvar element = arr[i];');
|
||||
assert.equal(editor.getModel()!.getLineContent(6), '\t\t');
|
||||
assert.equal(editor.getModel()!.getLineContent(7), '\t}');
|
||||
assert.strictEqual(editor.getModel()!.getLineContent(4), '\tfor (var i; i < arr.length; i++) {');
|
||||
assert.strictEqual(editor.getModel()!.getLineContent(5), '\t\tvar element = arr[i];');
|
||||
assert.strictEqual(editor.getModel()!.getLineContent(6), '\t\t');
|
||||
assert.strictEqual(editor.getModel()!.getLineContent(7), '\t}');
|
||||
|
||||
snippetController.prev();
|
||||
editor.trigger('test', 'type', { text: 'j' });
|
||||
assert.equal(editor.getModel()!.getLineContent(4), '\tfor (var j; j < arr.length; j++) {');
|
||||
assert.equal(editor.getModel()!.getLineContent(5), '\t\tvar element = arr[j];');
|
||||
assert.equal(editor.getModel()!.getLineContent(6), '\t\t');
|
||||
assert.equal(editor.getModel()!.getLineContent(7), '\t}');
|
||||
assert.strictEqual(editor.getModel()!.getLineContent(4), '\tfor (var j; j < arr.length; j++) {');
|
||||
assert.strictEqual(editor.getModel()!.getLineContent(5), '\t\tvar element = arr[j];');
|
||||
assert.strictEqual(editor.getModel()!.getLineContent(6), '\t\t');
|
||||
assert.strictEqual(editor.getModel()!.getLineContent(7), '\t}');
|
||||
|
||||
snippetController.next();
|
||||
snippetController.next();
|
||||
assert.deepEqual(editor.getPosition(), new Position(6, 3));
|
||||
assert.deepStrictEqual(editor.getPosition(), new Position(6, 3));
|
||||
});
|
||||
});
|
||||
|
||||
@@ -98,13 +98,13 @@ suite('SnippetController', () => {
|
||||
editor.setPosition({ lineNumber: 4, column: 2 });
|
||||
|
||||
snippetController.insert(template);
|
||||
assert.equal(editor.getModel()!.getLineContent(4), '\tfor (var index; index < array.length; index++) {');
|
||||
assert.equal(editor.getModel()!.getLineContent(5), '\t\tvar element = array[index];');
|
||||
assert.equal(editor.getModel()!.getLineContent(6), '\t\t');
|
||||
assert.equal(editor.getModel()!.getLineContent(7), '\t}');
|
||||
assert.strictEqual(editor.getModel()!.getLineContent(4), '\tfor (var index; index < array.length; index++) {');
|
||||
assert.strictEqual(editor.getModel()!.getLineContent(5), '\t\tvar element = array[index];');
|
||||
assert.strictEqual(editor.getModel()!.getLineContent(6), '\t\t');
|
||||
assert.strictEqual(editor.getModel()!.getLineContent(7), '\t}');
|
||||
|
||||
snippetController.cancel();
|
||||
assert.deepEqual(editor.getPosition(), new Position(4, 16));
|
||||
assert.deepStrictEqual(editor.getPosition(), new Position(4, 16));
|
||||
});
|
||||
});
|
||||
|
||||
@@ -121,7 +121,7 @@ suite('SnippetController', () => {
|
||||
// text: null
|
||||
// }]);
|
||||
|
||||
// assert.equal(snippetController.isInSnippetMode(), false);
|
||||
// assert.strictEqual(snippetController.isInSnippetMode(), false);
|
||||
// });
|
||||
// });
|
||||
|
||||
@@ -138,7 +138,7 @@ suite('SnippetController', () => {
|
||||
// text: null
|
||||
// }]);
|
||||
|
||||
// assert.equal(snippetController.isInSnippetMode(), false);
|
||||
// assert.strictEqual(snippetController.isInSnippetMode(), false);
|
||||
// });
|
||||
// });
|
||||
|
||||
@@ -155,7 +155,7 @@ suite('SnippetController', () => {
|
||||
// text: '\nHello'
|
||||
// }]);
|
||||
|
||||
// assert.equal(snippetController.isInSnippetMode(), false);
|
||||
// assert.strictEqual(snippetController.isInSnippetMode(), false);
|
||||
// });
|
||||
// });
|
||||
|
||||
@@ -172,7 +172,7 @@ suite('SnippetController', () => {
|
||||
// text: '\nHello'
|
||||
// }]);
|
||||
|
||||
// assert.equal(snippetController.isInSnippetMode(), false);
|
||||
// assert.strictEqual(snippetController.isInSnippetMode(), false);
|
||||
// });
|
||||
// });
|
||||
|
||||
@@ -183,7 +183,7 @@ suite('SnippetController', () => {
|
||||
|
||||
editor.getModel()!.setValue('goodbye');
|
||||
|
||||
assert.equal(snippetController.isInSnippetMode(), false);
|
||||
assert.strictEqual(snippetController.isInSnippetMode(), false);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -194,7 +194,7 @@ suite('SnippetController', () => {
|
||||
|
||||
editor.getModel()!.undo();
|
||||
|
||||
assert.equal(snippetController.isInSnippetMode(), false);
|
||||
assert.strictEqual(snippetController.isInSnippetMode(), false);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -205,7 +205,7 @@ suite('SnippetController', () => {
|
||||
|
||||
editor.setPosition({ lineNumber: 1, column: 1 });
|
||||
|
||||
assert.equal(snippetController.isInSnippetMode(), false);
|
||||
assert.strictEqual(snippetController.isInSnippetMode(), false);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -216,7 +216,7 @@ suite('SnippetController', () => {
|
||||
|
||||
editor.setModel(null);
|
||||
|
||||
assert.equal(snippetController.isInSnippetMode(), false);
|
||||
assert.strictEqual(snippetController.isInSnippetMode(), false);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -227,7 +227,7 @@ suite('SnippetController', () => {
|
||||
|
||||
snippetController.dispose();
|
||||
|
||||
assert.equal(snippetController.isInSnippetMode(), false);
|
||||
assert.strictEqual(snippetController.isInSnippetMode(), false);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -241,7 +241,7 @@ suite('SnippetController', () => {
|
||||
codeSnippet = 'foo$0';
|
||||
snippetController.insert(codeSnippet);
|
||||
|
||||
assert.equal(editor.getSelections()!.length, 2);
|
||||
assert.strictEqual(editor.getSelections()!.length, 2);
|
||||
const [first, second] = editor.getSelections()!;
|
||||
assert.ok(first.equalsRange({ startLineNumber: 1, startColumn: 4, endLineNumber: 1, endColumn: 4 }), first.toString());
|
||||
assert.ok(second.equalsRange({ startLineNumber: 2, startColumn: 4, endLineNumber: 2, endColumn: 4 }), second.toString());
|
||||
@@ -256,7 +256,7 @@ suite('SnippetController', () => {
|
||||
codeSnippet = 'foo$0bar';
|
||||
snippetController.insert(codeSnippet);
|
||||
|
||||
assert.equal(editor.getSelections()!.length, 2);
|
||||
assert.strictEqual(editor.getSelections()!.length, 2);
|
||||
const [first, second] = editor.getSelections()!;
|
||||
assert.ok(first.equalsRange({ startLineNumber: 1, startColumn: 4, endLineNumber: 1, endColumn: 4 }), first.toString());
|
||||
assert.ok(second.equalsRange({ startLineNumber: 2, startColumn: 4, endLineNumber: 2, endColumn: 4 }), second.toString());
|
||||
@@ -271,7 +271,7 @@ suite('SnippetController', () => {
|
||||
codeSnippet = 'foo$0bar';
|
||||
snippetController.insert(codeSnippet);
|
||||
|
||||
assert.equal(editor.getSelections()!.length, 2);
|
||||
assert.strictEqual(editor.getSelections()!.length, 2);
|
||||
const [first, second] = editor.getSelections()!;
|
||||
assert.ok(first.equalsRange({ startLineNumber: 1, startColumn: 4, endLineNumber: 1, endColumn: 4 }), first.toString());
|
||||
assert.ok(second.equalsRange({ startLineNumber: 1, startColumn: 14, endLineNumber: 1, endColumn: 14 }), second.toString());
|
||||
@@ -286,7 +286,7 @@ suite('SnippetController', () => {
|
||||
codeSnippet = 'foo\n$0\nbar';
|
||||
snippetController.insert(codeSnippet);
|
||||
|
||||
assert.equal(editor.getSelections()!.length, 2);
|
||||
assert.strictEqual(editor.getSelections()!.length, 2);
|
||||
const [first, second] = editor.getSelections()!;
|
||||
assert.ok(first.equalsRange({ startLineNumber: 2, startColumn: 1, endLineNumber: 2, endColumn: 1 }), first.toString());
|
||||
assert.ok(second.equalsRange({ startLineNumber: 4, startColumn: 1, endLineNumber: 4, endColumn: 1 }), second.toString());
|
||||
@@ -301,7 +301,7 @@ suite('SnippetController', () => {
|
||||
codeSnippet = 'foo\n$0\nbar';
|
||||
snippetController.insert(codeSnippet);
|
||||
|
||||
assert.equal(editor.getSelections()!.length, 2);
|
||||
assert.strictEqual(editor.getSelections()!.length, 2);
|
||||
const [first, second] = editor.getSelections()!;
|
||||
assert.ok(first.equalsRange({ startLineNumber: 2, startColumn: 1, endLineNumber: 2, endColumn: 1 }), first.toString());
|
||||
assert.ok(second.equalsRange({ startLineNumber: 4, startColumn: 1, endLineNumber: 4, endColumn: 1 }), second.toString());
|
||||
@@ -315,7 +315,7 @@ suite('SnippetController', () => {
|
||||
codeSnippet = 'xo$0r';
|
||||
snippetController.insert(codeSnippet, { overwriteBefore: 1 });
|
||||
|
||||
assert.equal(editor.getSelections()!.length, 1);
|
||||
assert.strictEqual(editor.getSelections()!.length, 1);
|
||||
assert.ok(editor.getSelection()!.equalsRange({ startLineNumber: 2, startColumn: 8, endColumn: 8, endLineNumber: 2 }));
|
||||
});
|
||||
});
|
||||
@@ -328,9 +328,9 @@ suite('SnippetController', () => {
|
||||
codeSnippet = '{{% url_**$1** %}}';
|
||||
controller.insert(codeSnippet, { overwriteBefore: 2 });
|
||||
|
||||
assert.equal(editor.getSelections()!.length, 1);
|
||||
assert.strictEqual(editor.getSelections()!.length, 1);
|
||||
assert.ok(editor.getSelection()!.equalsRange({ startLineNumber: 1, startColumn: 27, endLineNumber: 1, endColumn: 27 }));
|
||||
assert.equal(editor.getModel()!.getValue(), 'example example {{% url_**** %}}');
|
||||
assert.strictEqual(editor.getModel()!.getValue(), 'example example {{% url_**** %}}');
|
||||
|
||||
}, ['example example sc']);
|
||||
|
||||
@@ -346,9 +346,9 @@ suite('SnippetController', () => {
|
||||
|
||||
controller.insert(codeSnippet, { overwriteBefore: 2 });
|
||||
|
||||
assert.equal(editor.getSelections()!.length, 1);
|
||||
assert.strictEqual(editor.getSelections()!.length, 1);
|
||||
assert.ok(editor.getSelection()!.equalsRange({ startLineNumber: 2, startColumn: 2, endLineNumber: 2, endColumn: 2 }), editor.getSelection()!.toString());
|
||||
assert.equal(editor.getModel()!.getValue(), 'afterEach((done) => {\n\ttest\n});');
|
||||
assert.strictEqual(editor.getModel()!.getValue(), 'afterEach((done) => {\n\ttest\n});');
|
||||
|
||||
}, ['af']);
|
||||
|
||||
@@ -364,9 +364,9 @@ suite('SnippetController', () => {
|
||||
|
||||
controller.insert(codeSnippet, { overwriteBefore: 2 });
|
||||
|
||||
assert.equal(editor.getSelections()!.length, 1);
|
||||
assert.strictEqual(editor.getSelections()!.length, 1);
|
||||
assert.ok(editor.getSelection()!.equalsRange({ startLineNumber: 2, startColumn: 1, endLineNumber: 2, endColumn: 1 }), editor.getSelection()!.toString());
|
||||
assert.equal(editor.getModel()!.getValue(), 'afterEach((done) => {\n\ttest\n});');
|
||||
assert.strictEqual(editor.getModel()!.getValue(), 'afterEach((done) => {\n\ttest\n});');
|
||||
|
||||
}, ['af']);
|
||||
|
||||
@@ -380,8 +380,8 @@ suite('SnippetController', () => {
|
||||
|
||||
controller.insert(codeSnippet, { overwriteBefore: 8 });
|
||||
|
||||
assert.equal(editor.getModel()!.getValue(), 'after');
|
||||
assert.equal(editor.getSelections()!.length, 1);
|
||||
assert.strictEqual(editor.getModel()!.getValue(), 'after');
|
||||
assert.strictEqual(editor.getSelections()!.length, 1);
|
||||
assert.ok(editor.getSelection()!.equalsRange({ startLineNumber: 1, startColumn: 4, endLineNumber: 1, endColumn: 4 }), editor.getSelection()!.toString());
|
||||
|
||||
}, ['afterone']);
|
||||
@@ -404,7 +404,7 @@ suite('SnippetController', () => {
|
||||
|
||||
controller.insert(codeSnippet, { overwriteBefore: 2 });
|
||||
|
||||
assert.equal(editor.getSelections()!.length, 2);
|
||||
assert.strictEqual(editor.getSelections()!.length, 2);
|
||||
const [first, second] = editor.getSelections()!;
|
||||
|
||||
assert.ok(first.equalsRange({ startLineNumber: 5, startColumn: 3, endLineNumber: 5, endColumn: 3 }), first.toString());
|
||||
@@ -429,7 +429,7 @@ suite('SnippetController', () => {
|
||||
|
||||
controller.insert(codeSnippet, { overwriteBefore: 2 });
|
||||
|
||||
assert.equal(editor.getSelections()!.length, 1);
|
||||
assert.strictEqual(editor.getSelections()!.length, 1);
|
||||
const [first] = editor.getSelections()!;
|
||||
|
||||
assert.ok(first.equalsRange({ startLineNumber: 2, startColumn: 3, endLineNumber: 2, endColumn: 3 }), first.toString());
|
||||
@@ -465,7 +465,7 @@ suite('SnippetController', () => {
|
||||
|
||||
codeSnippet = '_foo';
|
||||
controller.insert(codeSnippet, { overwriteBefore: 1 });
|
||||
assert.equal(editor.getModel()!.getValue(), 'this._foo\nabc_foo');
|
||||
assert.strictEqual(editor.getModel()!.getValue(), 'this._foo\nabc_foo');
|
||||
|
||||
}, ['this._', 'abc']);
|
||||
|
||||
@@ -478,7 +478,7 @@ suite('SnippetController', () => {
|
||||
|
||||
codeSnippet = 'XX';
|
||||
controller.insert(codeSnippet, { overwriteBefore: 1 });
|
||||
assert.equal(editor.getModel()!.getValue(), 'this.XX\nabcXX');
|
||||
assert.strictEqual(editor.getModel()!.getValue(), 'this.XX\nabcXX');
|
||||
|
||||
}, ['this._', 'abc']);
|
||||
|
||||
@@ -492,7 +492,7 @@ suite('SnippetController', () => {
|
||||
|
||||
codeSnippet = '_foo';
|
||||
controller.insert(codeSnippet, { overwriteBefore: 1 });
|
||||
assert.equal(editor.getModel()!.getValue(), 'this._foo\nabc_foo\ndef_foo');
|
||||
assert.strictEqual(editor.getModel()!.getValue(), 'this._foo\nabc_foo\ndef_foo');
|
||||
|
||||
}, ['this._', 'abc', 'def_']);
|
||||
|
||||
@@ -506,7 +506,7 @@ suite('SnippetController', () => {
|
||||
|
||||
codeSnippet = '._foo';
|
||||
controller.insert(codeSnippet, { overwriteBefore: 2 });
|
||||
assert.equal(editor.getModel()!.getValue(), 'this._foo\nabc._foo\ndef._foo');
|
||||
assert.strictEqual(editor.getModel()!.getValue(), 'this._foo\nabc._foo\ndef._foo');
|
||||
|
||||
}, ['this._', 'abc', 'def._']);
|
||||
|
||||
@@ -520,7 +520,7 @@ suite('SnippetController', () => {
|
||||
|
||||
codeSnippet = '._foo';
|
||||
controller.insert(codeSnippet, { overwriteBefore: 2 });
|
||||
assert.equal(editor.getModel()!.getValue(), 'this._foo\nabc._foo\ndef._foo');
|
||||
assert.strictEqual(editor.getModel()!.getValue(), 'this._foo\nabc._foo\ndef._foo');
|
||||
|
||||
}, ['this._', 'abc', 'def._']);
|
||||
|
||||
@@ -534,7 +534,7 @@ suite('SnippetController', () => {
|
||||
|
||||
codeSnippet = '._foo';
|
||||
controller.insert(codeSnippet, { overwriteBefore: 2 });
|
||||
assert.equal(editor.getModel()!.getValue(), 'this._._foo\na._foo\ndef._._foo');
|
||||
assert.strictEqual(editor.getModel()!.getValue(), 'this._._foo\na._foo\ndef._._foo');
|
||||
|
||||
}, ['this._', 'abc', 'def._']);
|
||||
|
||||
@@ -550,7 +550,7 @@ suite('SnippetController', () => {
|
||||
|
||||
codeSnippet = 'document';
|
||||
controller.insert(codeSnippet, { overwriteBefore: 3 });
|
||||
assert.equal(editor.getModel()!.getValue(), '{document}\n{document && true}');
|
||||
assert.strictEqual(editor.getModel()!.getValue(), '{document}\n{document && true}');
|
||||
|
||||
}, ['{foo}', '{foo && true}']);
|
||||
});
|
||||
@@ -565,7 +565,7 @@ suite('SnippetController', () => {
|
||||
|
||||
codeSnippet = 'for (var ${1:i}=0; ${1:i}<len; ${1:i}++) { $0 }';
|
||||
controller.insert(codeSnippet);
|
||||
assert.equal(editor.getModel()!.getValue(), 'for (var i=0; i<len; i++) { }for (var i=0; i<len; i++) { }');
|
||||
assert.strictEqual(editor.getModel()!.getValue(), 'for (var i=0; i<len; i++) { }for (var i=0; i<len; i++) { }');
|
||||
|
||||
}, ['for (var i=0; i<len; i++) { }']);
|
||||
|
||||
@@ -578,7 +578,7 @@ suite('SnippetController', () => {
|
||||
|
||||
codeSnippet = 'for (let ${1:i}=0; ${1:i}<len; ${1:i}++) { $0 }';
|
||||
controller.insert(codeSnippet);
|
||||
assert.equal(editor.getModel()!.getValue(), 'for (let i=0; i<len; i++) { }for (var i=0; i<len; i++) { }');
|
||||
assert.strictEqual(editor.getModel()!.getValue(), 'for (let i=0; i<len; i++) { }for (var i=0; i<len; i++) { }');
|
||||
|
||||
}, ['for (var i=0; i<len; i++) { }']);
|
||||
|
||||
|
||||
@@ -21,13 +21,13 @@ suite('SnippetController2', function () {
|
||||
const actual = s.shift()!;
|
||||
assert.ok(selection.equalsSelection(actual), `actual=${selection.toString()} <> expected=${actual.toString()}`);
|
||||
}
|
||||
assert.equal(s.length, 0);
|
||||
assert.strictEqual(s.length, 0);
|
||||
}
|
||||
|
||||
function assertContextKeys(service: MockContextKeyService, inSnippet: boolean, hasPrev: boolean, hasNext: boolean): void {
|
||||
assert.equal(SnippetController2.InSnippetMode.getValue(service), inSnippet, `inSnippetMode`);
|
||||
assert.equal(SnippetController2.HasPrevTabstop.getValue(service), hasPrev, `HasPrevTabstop`);
|
||||
assert.equal(SnippetController2.HasNextTabstop.getValue(service), hasNext, `HasNextTabstop`);
|
||||
assert.strictEqual(SnippetController2.InSnippetMode.getValue(service), inSnippet, `inSnippetMode`);
|
||||
assert.strictEqual(SnippetController2.HasPrevTabstop.getValue(service), hasPrev, `HasPrevTabstop`);
|
||||
assert.strictEqual(SnippetController2.HasNextTabstop.getValue(service), hasNext, `HasNextTabstop`);
|
||||
}
|
||||
|
||||
let editor: ICodeEditor;
|
||||
@@ -40,7 +40,7 @@ suite('SnippetController2', function () {
|
||||
model = createTextModel('if\n $state\nfi');
|
||||
editor = createTestCodeEditor({ model: model });
|
||||
editor.setSelections([new Selection(1, 1, 1, 1), new Selection(2, 5, 2, 5)]);
|
||||
assert.equal(model.getEOL(), '\n');
|
||||
assert.strictEqual(model.getEOL(), '\n');
|
||||
});
|
||||
|
||||
teardown(function () {
|
||||
@@ -78,9 +78,9 @@ suite('SnippetController2', function () {
|
||||
assertContextKeys(contextKeys, false, false, false);
|
||||
|
||||
editor.trigger('test', 'type', { text: '\t' });
|
||||
assert.equal(SnippetController2.InSnippetMode.getValue(contextKeys), false);
|
||||
assert.equal(SnippetController2.HasNextTabstop.getValue(contextKeys), false);
|
||||
assert.equal(SnippetController2.HasPrevTabstop.getValue(contextKeys), false);
|
||||
assert.strictEqual(SnippetController2.InSnippetMode.getValue(contextKeys), false);
|
||||
assert.strictEqual(SnippetController2.HasNextTabstop.getValue(contextKeys), false);
|
||||
assert.strictEqual(SnippetController2.HasPrevTabstop.getValue(contextKeys), false);
|
||||
});
|
||||
|
||||
test('insert, insert -> cursor moves out (left/right)', function () {
|
||||
@@ -111,7 +111,7 @@ suite('SnippetController2', function () {
|
||||
const ctrl = new SnippetController2(editor, logService, contextKeys);
|
||||
|
||||
ctrl.insert('foo${1:bar}foo$0');
|
||||
assert.equal(SnippetController2.InSnippetMode.getValue(contextKeys), true);
|
||||
assert.strictEqual(SnippetController2.InSnippetMode.getValue(contextKeys), true);
|
||||
assertSelections(editor, new Selection(1, 4, 1, 7), new Selection(2, 8, 2, 11));
|
||||
|
||||
// bad selection change
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user