mirror of
https://github.com/ckaczor/azuredatastudio.git
synced 2026-02-12 19:18:32 -05:00
Merge from vscode 2e5312cd61ff99c570299ecc122c52584265eda2
This commit is contained in:
committed by
Anthony Dresser
parent
3603f55d97
commit
7f1d8fc32f
@@ -3,7 +3,6 @@
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import * as browser from 'vs/base/browser/browser';
|
||||
import * as dom from 'vs/base/browser/dom';
|
||||
import { StandardWheelEvent, IMouseWheelEvent } from 'vs/base/browser/mouseEvent';
|
||||
import { TimeoutTimer } from 'vs/base/common/async';
|
||||
@@ -119,7 +118,7 @@ export class MouseHandler extends ViewEventHandler {
|
||||
e.stopPropagation();
|
||||
}
|
||||
};
|
||||
this._register(dom.addDisposableListener(this.viewHelper.viewDomNode, browser.isEdge ? 'mousewheel' : 'wheel', onMouseWheel, { capture: true, passive: false }));
|
||||
this._register(dom.addDisposableListener(this.viewHelper.viewDomNode, dom.EventType.MOUSE_WHEEL, onMouseWheel, { capture: true, passive: false }));
|
||||
|
||||
this._context.addEventHandler(this);
|
||||
}
|
||||
|
||||
@@ -125,6 +125,7 @@ export class TextAreaHandler extends ViewPart {
|
||||
this.textArea.setAttribute('spellcheck', 'false');
|
||||
this.textArea.setAttribute('aria-label', this._getAriaLabel(options));
|
||||
this.textArea.setAttribute('role', 'textbox');
|
||||
this.textArea.setAttribute('aria-roledescription', nls.localize('editor', "editor"));
|
||||
this.textArea.setAttribute('aria-multiline', 'true');
|
||||
this.textArea.setAttribute('aria-haspopup', 'false');
|
||||
this.textArea.setAttribute('aria-autocomplete', 'both');
|
||||
|
||||
@@ -136,6 +136,8 @@ export class View extends ViewEventHandler {
|
||||
|
||||
this.domNode = createFastDomNode(document.createElement('div'));
|
||||
this.domNode.setClassName(this.getEditorClassName());
|
||||
// Set role 'code' for better screen reader support https://github.com/microsoft/vscode/issues/93438
|
||||
this.domNode.setAttribute('role', 'code');
|
||||
|
||||
this.overflowGuardContainer = createFastDomNode(document.createElement('div'));
|
||||
PartFingerprints.write(this.overflowGuardContainer, PartFingerprint.OverflowGuard);
|
||||
|
||||
@@ -49,6 +49,7 @@ import { onUnexpectedError } from 'vs/base/common/errors';
|
||||
import { IEditorProgressService, IProgressRunner } from 'vs/platform/progress/common/progress';
|
||||
import { ElementSizeObserver } from 'vs/editor/browser/config/elementSizeObserver';
|
||||
import { reverseLineChanges } from 'sql/editor/browser/diffEditorHelper';
|
||||
import { Codicon, registerIcon } from 'vs/base/common/codicons';
|
||||
|
||||
interface IEditorDiffDecorations {
|
||||
decorations: IModelDeltaDecoration[];
|
||||
@@ -159,6 +160,10 @@ class VisualEditorState {
|
||||
|
||||
let DIFF_EDITOR_ID = 0;
|
||||
|
||||
|
||||
const diffInsertIcon = registerIcon('diff-insert', Codicon.add);
|
||||
const diffRemoveIcon = registerIcon('diff-remove', Codicon.remove);
|
||||
|
||||
export class DiffEditorWidget extends Disposable implements editorBrowser.IDiffEditor {
|
||||
|
||||
private static readonly ONE_OVERVIEW_WIDTH = 15;
|
||||
@@ -1630,7 +1635,7 @@ const DECORATIONS = {
|
||||
}),
|
||||
lineInsertWithSign: ModelDecorationOptions.register({
|
||||
className: 'line-insert',
|
||||
linesDecorationsClassName: 'insert-sign codicon codicon-add',
|
||||
linesDecorationsClassName: 'insert-sign ' + diffInsertIcon.classNames,
|
||||
marginClassName: 'line-insert',
|
||||
isWholeLine: true
|
||||
}),
|
||||
@@ -1642,7 +1647,7 @@ const DECORATIONS = {
|
||||
}),
|
||||
lineDeleteWithSign: ModelDecorationOptions.register({
|
||||
className: 'line-delete',
|
||||
linesDecorationsClassName: 'delete-sign codicon codicon-remove',
|
||||
linesDecorationsClassName: 'delete-sign ' + diffRemoveIcon.classNames,
|
||||
marginClassName: 'line-delete',
|
||||
isWholeLine: true
|
||||
|
||||
@@ -2101,7 +2106,7 @@ class InlineViewZonesComputer extends ViewZonesComputer {
|
||||
if (this.renderIndicators) {
|
||||
let index = lineNumber - lineChange.originalStartLineNumber;
|
||||
marginHTML = marginHTML.concat([
|
||||
`<div class="delete-sign codicon codicon-remove" style="position:absolute;top:${index * lineHeight}px;width:${lineDecorationsWidth}px;height:${lineHeight}px;right:0;"></div>`
|
||||
`<div class="delete-sign ${diffRemoveIcon.classNames}" style="position:absolute;top:${index * lineHeight}px;width:${lineDecorationsWidth}px;height:${lineHeight}px;right:0;"></div>`
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -31,6 +31,7 @@ import { KeybindingWeight } from 'vs/platform/keybinding/common/keybindingsRegis
|
||||
import { scrollbarShadow } from 'vs/platform/theme/common/colorRegistry';
|
||||
import { registerThemingParticipant } from 'vs/platform/theme/common/themeService';
|
||||
import { Constants } from 'vs/base/common/uint';
|
||||
import { registerIcon, Codicon } from 'vs/base/common/codicons';
|
||||
|
||||
const DIFF_LINES_PADDING = 3;
|
||||
|
||||
@@ -72,6 +73,10 @@ class Diff {
|
||||
}
|
||||
}
|
||||
|
||||
const diffReviewInsertIcon = registerIcon('diff-review-insert', Codicon.add);
|
||||
const diffReviewRemoveIcon = registerIcon('diff-review-remove', Codicon.remove);
|
||||
const diffReviewCloseIcon = registerIcon('diff-review-close', Codicon.close);
|
||||
|
||||
export class DiffReview extends Disposable {
|
||||
|
||||
private readonly _diffEditor: DiffEditorWidget;
|
||||
@@ -99,7 +104,7 @@ export class DiffReview extends Disposable {
|
||||
this.actionBarContainer.domNode
|
||||
));
|
||||
|
||||
this._actionBar.push(new Action('diffreview.close', nls.localize('label.close', "Close"), 'close-diff-review codicon-close', true, () => {
|
||||
this._actionBar.push(new Action('diffreview.close', nls.localize('label.close', "Close"), 'close-diff-review ' + diffReviewCloseIcon.classNames, true, () => {
|
||||
this.hide();
|
||||
return Promise.resolve(null);
|
||||
}), { label: false, icon: true });
|
||||
@@ -639,17 +644,17 @@ export class DiffReview extends Disposable {
|
||||
let rowClassName: string = 'diff-review-row';
|
||||
let lineNumbersExtraClassName: string = '';
|
||||
const spacerClassName: string = 'diff-review-spacer';
|
||||
let spacerCodiconName: string | null = null;
|
||||
let spacerIcon: Codicon | null = null;
|
||||
switch (type) {
|
||||
case DiffEntryType.Insert:
|
||||
rowClassName = 'diff-review-row line-insert';
|
||||
lineNumbersExtraClassName = ' char-insert';
|
||||
spacerCodiconName = 'codicon codicon-add';
|
||||
spacerIcon = diffReviewInsertIcon;
|
||||
break;
|
||||
case DiffEntryType.Delete:
|
||||
rowClassName = 'diff-review-row line-delete';
|
||||
lineNumbersExtraClassName = ' char-delete';
|
||||
spacerCodiconName = 'codicon codicon-remove';
|
||||
spacerIcon = diffReviewRemoveIcon;
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -713,9 +718,9 @@ export class DiffReview extends Disposable {
|
||||
const spacer = document.createElement('span');
|
||||
spacer.className = spacerClassName;
|
||||
|
||||
if (spacerCodiconName) {
|
||||
if (spacerIcon) {
|
||||
const spacerCodicon = document.createElement('span');
|
||||
spacerCodicon.className = spacerCodiconName;
|
||||
spacerCodicon.className = spacerIcon.classNames;
|
||||
spacerCodicon.innerHTML = '  ';
|
||||
spacer.appendChild(spacerCodicon);
|
||||
} else {
|
||||
|
||||
@@ -13,6 +13,7 @@ import { IEditorMouseEvent, MouseTargetType } from 'vs/editor/browser/editorBrow
|
||||
import { Range } from 'vs/editor/common/core/range';
|
||||
import { CodeEditorWidget } from 'vs/editor/browser/widget/codeEditorWidget';
|
||||
import { EditorOption } from 'vs/editor/common/config/editorOptions';
|
||||
import { Codicon } from 'vs/base/common/codicons';
|
||||
|
||||
export interface IDiffLinesChange {
|
||||
readonly originalStartLineNumber: number;
|
||||
@@ -57,7 +58,7 @@ export class InlineDiffMargin extends Disposable {
|
||||
this._marginDomNode.style.zIndex = '10';
|
||||
|
||||
this._diffActions = document.createElement('div');
|
||||
this._diffActions.className = 'codicon codicon-lightbulb lightbulb-glyph';
|
||||
this._diffActions.className = Codicon.lightBulb.classNames + ' lightbulb-glyph';
|
||||
this._diffActions.style.position = 'absolute';
|
||||
const lineHeight = editor.getOption(EditorOption.lineHeight);
|
||||
const lineFeed = editor.getModel()!.getEOL();
|
||||
|
||||
@@ -1073,7 +1073,7 @@ class EditorComments extends BaseEditorOption<EditorOption.comments, EditorComme
|
||||
}
|
||||
|
||||
public validate(_input: any): EditorCommentsOptions {
|
||||
if (typeof _input !== 'object') {
|
||||
if (!_input || typeof _input !== 'object') {
|
||||
return this.defaultValue;
|
||||
}
|
||||
const input = _input as IEditorCommentsOptions;
|
||||
@@ -1259,6 +1259,10 @@ export interface IEditorFindOptions {
|
||||
* Controls if the Find Widget should read or modify the shared find clipboard on macOS
|
||||
*/
|
||||
globalFindClipboard?: boolean;
|
||||
/**
|
||||
* Controls whether the search automatically restarts from the beginning (or the end) when no further matches can be found
|
||||
*/
|
||||
loop?: boolean;
|
||||
}
|
||||
|
||||
export type EditorFindOptions = Readonly<Required<IEditorFindOptions>>;
|
||||
@@ -1270,7 +1274,8 @@ class EditorFind extends BaseEditorOption<EditorOption.find, EditorFindOptions>
|
||||
seedSearchStringFromSelection: true,
|
||||
autoFindInSelection: 'never',
|
||||
globalFindClipboard: false,
|
||||
addExtraSpaceOnTop: true
|
||||
addExtraSpaceOnTop: true,
|
||||
loop: true
|
||||
};
|
||||
super(
|
||||
EditorOption.find, 'find', defaults,
|
||||
@@ -1301,13 +1306,19 @@ class EditorFind extends BaseEditorOption<EditorOption.find, EditorFindOptions>
|
||||
type: 'boolean',
|
||||
default: defaults.addExtraSpaceOnTop,
|
||||
description: nls.localize('find.addExtraSpaceOnTop', "Controls whether the Find Widget should add extra lines on top of the editor. When true, you can scroll beyond the first line when the Find Widget is visible.")
|
||||
}
|
||||
},
|
||||
'editor.find.loop': {
|
||||
type: 'boolean',
|
||||
default: defaults.loop,
|
||||
description: nls.localize('find.loop', "Controls whether the search automatically restarts from the beginning (or the end) when no further matches can be found.")
|
||||
},
|
||||
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
public validate(_input: any): EditorFindOptions {
|
||||
if (typeof _input !== 'object') {
|
||||
if (!_input || typeof _input !== 'object') {
|
||||
return this.defaultValue;
|
||||
}
|
||||
const input = _input as IEditorFindOptions;
|
||||
@@ -1317,7 +1328,8 @@ class EditorFind extends BaseEditorOption<EditorOption.find, EditorFindOptions>
|
||||
? (_input.autoFindInSelection ? 'always' : 'never')
|
||||
: EditorStringEnumOption.stringSet<'never' | 'always' | 'multiline'>(input.autoFindInSelection, this.defaultValue.autoFindInSelection, ['never', 'always', 'multiline']),
|
||||
globalFindClipboard: EditorBooleanOption.boolean(input.globalFindClipboard, this.defaultValue.globalFindClipboard),
|
||||
addExtraSpaceOnTop: EditorBooleanOption.boolean(input.addExtraSpaceOnTop, this.defaultValue.addExtraSpaceOnTop)
|
||||
addExtraSpaceOnTop: EditorBooleanOption.boolean(input.addExtraSpaceOnTop, this.defaultValue.addExtraSpaceOnTop),
|
||||
loop: EditorBooleanOption.boolean(input.loop, this.defaultValue.loop),
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -1532,7 +1544,7 @@ class EditorGoToLocation extends BaseEditorOption<EditorOption.gotoLocation, GoT
|
||||
}
|
||||
|
||||
public validate(_input: any): GoToLocationOptions {
|
||||
if (typeof _input !== 'object') {
|
||||
if (!_input || typeof _input !== 'object') {
|
||||
return this.defaultValue;
|
||||
}
|
||||
const input = _input as IGotoLocationOptions;
|
||||
@@ -1610,7 +1622,7 @@ class EditorHover extends BaseEditorOption<EditorOption.hover, EditorHoverOption
|
||||
}
|
||||
|
||||
public validate(_input: any): EditorHoverOptions {
|
||||
if (typeof _input !== 'object') {
|
||||
if (!_input || typeof _input !== 'object') {
|
||||
return this.defaultValue;
|
||||
}
|
||||
const input = _input as IEditorHoverOptions;
|
||||
@@ -2036,7 +2048,7 @@ class EditorLightbulb extends BaseEditorOption<EditorOption.lightbulb, EditorLig
|
||||
}
|
||||
|
||||
public validate(_input: any): EditorLightbulbOptions {
|
||||
if (typeof _input !== 'object') {
|
||||
if (!_input || typeof _input !== 'object') {
|
||||
return this.defaultValue;
|
||||
}
|
||||
const input = _input as IEditorLightbulbOptions;
|
||||
@@ -2180,7 +2192,7 @@ class EditorMinimap extends BaseEditorOption<EditorOption.minimap, EditorMinimap
|
||||
}
|
||||
|
||||
public validate(_input: any): EditorMinimapOptions {
|
||||
if (typeof _input !== 'object') {
|
||||
if (!_input || typeof _input !== 'object') {
|
||||
return this.defaultValue;
|
||||
}
|
||||
const input = _input as IEditorMinimapOptions;
|
||||
@@ -2255,7 +2267,7 @@ class EditorPadding extends BaseEditorOption<EditorOption.padding, InternalEdito
|
||||
}
|
||||
|
||||
public validate(_input: any): InternalEditorPaddingOptions {
|
||||
if (typeof _input !== 'object') {
|
||||
if (!_input || typeof _input !== 'object') {
|
||||
return this.defaultValue;
|
||||
}
|
||||
const input = _input as IEditorPaddingOptions;
|
||||
@@ -2313,7 +2325,7 @@ class EditorParameterHints extends BaseEditorOption<EditorOption.parameterHints,
|
||||
}
|
||||
|
||||
public validate(_input: any): InternalParameterHintOptions {
|
||||
if (typeof _input !== 'object') {
|
||||
if (!_input || typeof _input !== 'object') {
|
||||
return this.defaultValue;
|
||||
}
|
||||
const input = _input as IEditorParameterHintOptions;
|
||||
@@ -2403,7 +2415,7 @@ class EditorQuickSuggestions extends BaseEditorOption<EditorOption.quickSuggesti
|
||||
if (typeof _input === 'boolean') {
|
||||
return _input;
|
||||
}
|
||||
if (typeof _input === 'object') {
|
||||
if (_input && typeof _input === 'object') {
|
||||
const input = _input as IQuickSuggestionsOptions;
|
||||
const opts = {
|
||||
other: EditorBooleanOption.boolean(input.other, this.defaultValue.other),
|
||||
@@ -2553,7 +2565,7 @@ class EditorRulers extends BaseEditorOption<EditorOption.rulers, IRulerOption[]>
|
||||
column: EditorIntOption.clampedInt(_element, 0, 0, 10000),
|
||||
color: null
|
||||
});
|
||||
} else if (typeof _element === 'object') {
|
||||
} else if (_element && typeof _element === 'object') {
|
||||
const element = _element as IRulerOption;
|
||||
rulers.push({
|
||||
column: EditorIntOption.clampedInt(element.column, 0, 0, 10000),
|
||||
@@ -2687,7 +2699,7 @@ class EditorScrollbar extends BaseEditorOption<EditorOption.scrollbar, InternalE
|
||||
}
|
||||
|
||||
public validate(_input: any): InternalEditorScrollbarOptions {
|
||||
if (typeof _input !== 'object') {
|
||||
if (!_input || typeof _input !== 'object') {
|
||||
return this.defaultValue;
|
||||
}
|
||||
const input = _input as IEditorScrollbarOptions;
|
||||
@@ -3108,7 +3120,7 @@ class EditorSuggest extends BaseEditorOption<EditorOption.suggest, InternalSugge
|
||||
}
|
||||
|
||||
public validate(_input: any): InternalSuggestOptions {
|
||||
if (typeof _input !== 'object') {
|
||||
if (!_input || typeof _input !== 'object') {
|
||||
return this.defaultValue;
|
||||
}
|
||||
const input = _input as ISuggestOptions;
|
||||
|
||||
@@ -10,6 +10,7 @@ export namespace EditorContextKeys {
|
||||
export const editorSimpleInput = new RawContextKey<boolean>('editorSimpleInput', false);
|
||||
/**
|
||||
* A context key that is set when the editor's text has focus (cursor is blinking).
|
||||
* Is false when focus is in simple editor widgets (repl input, scm commit input).
|
||||
*/
|
||||
export const editorTextFocus = new RawContextKey<boolean>('editorTextFocus', false);
|
||||
/**
|
||||
|
||||
@@ -56,77 +56,80 @@ export function ensureValidWordDefinition(wordDefinition?: RegExp | null): RegEx
|
||||
return result;
|
||||
}
|
||||
|
||||
function getWordAtPosFast(column: number, wordDefinition: RegExp, text: string, textOffset: number): IWordAtPosition | null {
|
||||
// find whitespace enclosed text around column and match from there
|
||||
const _defaultConfig = {
|
||||
maxLen: 1000,
|
||||
windowSize: 15,
|
||||
timeBudget: 150
|
||||
};
|
||||
|
||||
let pos = column - 1 - textOffset;
|
||||
let start = text.lastIndexOf(' ', pos - 1) + 1;
|
||||
export function getWordAtText(column: number, wordDefinition: RegExp, text: string, textOffset: number, config = _defaultConfig): IWordAtPosition | null {
|
||||
|
||||
wordDefinition.lastIndex = start;
|
||||
if (text.length > config.maxLen) {
|
||||
// don't throw strings that long at the regexp
|
||||
// but use a sub-string in which a word must occur
|
||||
let start = column - config.maxLen / 2;
|
||||
if (start < 0) {
|
||||
textOffset += column;
|
||||
start = 0;
|
||||
} else {
|
||||
textOffset += start;
|
||||
}
|
||||
text = text.substring(start, column + config.maxLen / 2);
|
||||
return getWordAtText(column, wordDefinition, text, textOffset, config);
|
||||
}
|
||||
|
||||
const t1 = Date.now();
|
||||
const pos = column - 1 - textOffset;
|
||||
|
||||
let prevRegexIndex = -1;
|
||||
let match: RegExpMatchArray | null = null;
|
||||
|
||||
for (let i = 1; ; i++) {
|
||||
// check time budget
|
||||
if (Date.now() - t1 >= config.timeBudget) {
|
||||
// break;
|
||||
}
|
||||
|
||||
// reset the index at which the regexp should start matching, also know where it
|
||||
// should stop so that subsequent search don't repeat previous searches
|
||||
const regexIndex = pos - config.windowSize * i;
|
||||
wordDefinition.lastIndex = Math.max(0, regexIndex);
|
||||
match = _findRegexMatchEnclosingPosition(wordDefinition, text, pos, prevRegexIndex);
|
||||
|
||||
// stop: found something
|
||||
if (match) {
|
||||
break;
|
||||
}
|
||||
|
||||
// stop: searched at start
|
||||
if (regexIndex <= 0) {
|
||||
break;
|
||||
}
|
||||
prevRegexIndex = regexIndex;
|
||||
}
|
||||
|
||||
if (match) {
|
||||
let result = {
|
||||
word: match[0],
|
||||
startColumn: textOffset + 1 + match.index!,
|
||||
endColumn: textOffset + 1 + wordDefinition.lastIndex
|
||||
};
|
||||
wordDefinition.lastIndex = 0;
|
||||
return result;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
function _findRegexMatchEnclosingPosition(wordDefinition: RegExp, text: string, pos: number, stopPos: number): RegExpMatchArray | null {
|
||||
let match: RegExpMatchArray | null;
|
||||
while (match = wordDefinition.exec(text)) {
|
||||
const matchIndex = match.index || 0;
|
||||
if (matchIndex <= pos && wordDefinition.lastIndex >= pos) {
|
||||
return {
|
||||
word: match[0],
|
||||
startColumn: textOffset + 1 + matchIndex,
|
||||
endColumn: textOffset + 1 + wordDefinition.lastIndex
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
function getWordAtPosSlow(column: number, wordDefinition: RegExp, text: string, textOffset: number): IWordAtPosition | null {
|
||||
// matches all words starting at the beginning
|
||||
// of the input until it finds a match that encloses
|
||||
// the desired column. slow but correct
|
||||
|
||||
let pos = column - 1 - textOffset;
|
||||
wordDefinition.lastIndex = 0;
|
||||
|
||||
let match: RegExpMatchArray | null;
|
||||
while (match = wordDefinition.exec(text)) {
|
||||
const matchIndex = match.index || 0;
|
||||
if (matchIndex > pos) {
|
||||
// |nW -> matched only after the pos
|
||||
return match;
|
||||
} else if (stopPos > 0 && matchIndex > stopPos) {
|
||||
return null;
|
||||
|
||||
} else if (wordDefinition.lastIndex >= pos) {
|
||||
// W|W -> match encloses pos
|
||||
return {
|
||||
word: match[0],
|
||||
startColumn: textOffset + 1 + matchIndex,
|
||||
endColumn: textOffset + 1 + wordDefinition.lastIndex
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
export function getWordAtText(column: number, wordDefinition: RegExp, text: string, textOffset: number): IWordAtPosition | null {
|
||||
|
||||
// if `words` can contain whitespace character we have to use the slow variant
|
||||
// otherwise we use the fast variant of finding a word
|
||||
wordDefinition.lastIndex = 0;
|
||||
let match = wordDefinition.exec(text);
|
||||
if (!match) {
|
||||
return null;
|
||||
}
|
||||
// todo@joh the `match` could already be the (first) word
|
||||
const ret = match[0].indexOf(' ') >= 0
|
||||
// did match a word which contains a space character -> use slow word find
|
||||
? getWordAtPosSlow(column, wordDefinition, text, textOffset)
|
||||
// sane word definition -> use fast word find
|
||||
: getWordAtPosFast(column, wordDefinition, text, textOffset);
|
||||
|
||||
// both (getWordAtPosFast and getWordAtPosSlow) leave the wordDefinition-RegExp
|
||||
// in an undefined state and to not confuse other users of the wordDefinition
|
||||
// we reset the lastIndex
|
||||
wordDefinition.lastIndex = 0;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -19,6 +19,7 @@ import { LanguageFeatureRegistry } from 'vs/editor/common/modes/languageFeatureR
|
||||
import { TokenizationRegistryImpl } from 'vs/editor/common/modes/tokenizationRegistry';
|
||||
import { ExtensionIdentifier } from 'vs/platform/extensions/common/extensions';
|
||||
import { IMarkerData } from 'vs/platform/markers/common/markers';
|
||||
import { iconRegistry, Codicon } from 'vs/base/common/codicons';
|
||||
|
||||
/**
|
||||
* Open ended enum at runtime
|
||||
@@ -359,7 +360,13 @@ export const completionKindToCssClass = (function () {
|
||||
data[CompletionItemKind.Issue] = 'issues';
|
||||
|
||||
return function (kind: CompletionItemKind) {
|
||||
return data[kind] || 'property';
|
||||
const name = data[kind];
|
||||
let codicon = name && iconRegistry.get(name);
|
||||
if (!codicon) {
|
||||
console.info('No codicon found for CompletionItemKind ' + kind);
|
||||
codicon = Codicon.symbolProperty;
|
||||
}
|
||||
return codicon.classNames;
|
||||
};
|
||||
})();
|
||||
|
||||
@@ -697,6 +704,12 @@ export interface SignatureInformation {
|
||||
* The parameters of this signature.
|
||||
*/
|
||||
parameters: ParameterInformation[];
|
||||
/**
|
||||
* Index of the active parameter.
|
||||
*
|
||||
* If provided, this is used in place of `SignatureHelp.activeSignature`.
|
||||
*/
|
||||
activeParameter?: number;
|
||||
}
|
||||
/**
|
||||
* Signature help represents the signature of something
|
||||
@@ -1037,7 +1050,13 @@ export namespace SymbolKinds {
|
||||
* @internal
|
||||
*/
|
||||
export function toCssClassName(kind: SymbolKind, inline?: boolean): string {
|
||||
return `codicon ${inline ? 'inline' : 'block'} codicon-symbol-${byKind.get(kind) || 'property'}`;
|
||||
const symbolName = byKind.get(kind);
|
||||
let codicon = symbolName && iconRegistry.get('symbol-' + symbolName);
|
||||
if (!codicon) {
|
||||
console.info('No codicon found for SymbolKind ' + kind);
|
||||
codicon = Codicon.symbolProperty;
|
||||
}
|
||||
return `${inline ? 'inline' : 'block'} ${codicon.classNames}`;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1393,7 +1412,10 @@ export interface RenameProvider {
|
||||
export interface AuthenticationSession {
|
||||
id: string;
|
||||
getAccessToken(): Thenable<string>;
|
||||
accountName: string;
|
||||
account: {
|
||||
displayName: string;
|
||||
id: string;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -114,7 +114,7 @@ class EditorScrollable extends Disposable {
|
||||
scrollWidth: dimensions.scrollWidth,
|
||||
height: dimensions.height,
|
||||
scrollHeight: dimensions.scrollHeight
|
||||
});
|
||||
}, true);
|
||||
|
||||
const contentWidthChanged = (oldDimensions.contentWidth !== dimensions.contentWidth);
|
||||
const contentHeightChanged = (oldDimensions.contentHeight !== dimensions.contentHeight);
|
||||
|
||||
@@ -35,6 +35,12 @@ export interface CodeActionSet extends IDisposable {
|
||||
class ManagedCodeActionSet extends Disposable implements CodeActionSet {
|
||||
|
||||
private static codeActionsComparator(a: modes.CodeAction, b: modes.CodeAction): number {
|
||||
if (a.isPreferred && !b.isPreferred) {
|
||||
return -1;
|
||||
} else if (!a.isPreferred && b.isPreferred) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (isNonEmptyArray(a.diagnostics)) {
|
||||
if (isNonEmptyArray(b.diagnostics)) {
|
||||
return a.diagnostics[0].message.localeCompare(b.diagnostics[0].message);
|
||||
|
||||
@@ -19,6 +19,7 @@ import { registerThemingParticipant, IColorTheme, ICssStyleCollector } from 'vs/
|
||||
import { editorLightBulbForeground, editorLightBulbAutoFixForeground } from 'vs/platform/theme/common/colorRegistry';
|
||||
import { Gesture } from 'vs/base/browser/touch';
|
||||
import type { CodeActionTrigger } from 'vs/editor/contrib/codeAction/types';
|
||||
import { Codicon } from 'vs/base/common/codicons';
|
||||
|
||||
namespace LightBulbState {
|
||||
|
||||
@@ -63,7 +64,7 @@ export class LightBulbWidget extends Disposable implements IContentWidget {
|
||||
) {
|
||||
super();
|
||||
this._domNode = document.createElement('div');
|
||||
this._domNode.className = 'codicon codicon-lightbulb';
|
||||
this._domNode.className = Codicon.lightBulb.classNames;
|
||||
|
||||
this._editor.addContentWidget(this);
|
||||
|
||||
@@ -121,8 +122,8 @@ export class LightBulbWidget extends Disposable implements IContentWidget {
|
||||
}
|
||||
}));
|
||||
|
||||
this._updateLightBulbTitle();
|
||||
this._register(this._keybindingService.onDidUpdateKeybindings(this._updateLightBulbTitle, this));
|
||||
this._updateLightBulbTitleAndIcon();
|
||||
this._register(this._keybindingService.onDidUpdateKeybindings(this._updateLightBulbTitleAndIcon, this));
|
||||
}
|
||||
|
||||
dispose(): void {
|
||||
@@ -184,7 +185,6 @@ export class LightBulbWidget extends Disposable implements IContentWidget {
|
||||
position: { lineNumber: effectiveLineNumber, column: 1 },
|
||||
preference: LightBulbWidget._posPref
|
||||
});
|
||||
dom.toggleClass(this._domNode, 'codicon-lightbulb-autofix', actions.hasAutoFix);
|
||||
this._editor.layoutContentWidget(this);
|
||||
}
|
||||
|
||||
@@ -197,11 +197,15 @@ export class LightBulbWidget extends Disposable implements IContentWidget {
|
||||
|
||||
private set state(value) {
|
||||
this._state = value;
|
||||
this._updateLightBulbTitle();
|
||||
this._updateLightBulbTitleAndIcon();
|
||||
}
|
||||
|
||||
private _updateLightBulbTitle(): void {
|
||||
private _updateLightBulbTitleAndIcon(): void {
|
||||
if (this.state.type === LightBulbState.Type.Showing && this.state.actions.hasAutoFix) {
|
||||
// update icon
|
||||
dom.removeClasses(this._domNode, Codicon.lightBulb.classNames);
|
||||
dom.addClasses(this._domNode, Codicon.lightbulbAutofix.classNames);
|
||||
|
||||
const preferredKb = this._keybindingService.lookupKeybinding(this._preferredFixActionId);
|
||||
if (preferredKb) {
|
||||
this.title = nls.localize('prefferedQuickFixWithKb', "Show Fixes. Preferred Fix Available ({0})", preferredKb.getLabel());
|
||||
@@ -209,6 +213,10 @@ export class LightBulbWidget extends Disposable implements IContentWidget {
|
||||
}
|
||||
}
|
||||
|
||||
// update icon
|
||||
dom.removeClasses(this._domNode, Codicon.lightbulbAutofix.classNames);
|
||||
dom.addClasses(this._domNode, Codicon.lightBulb.classNames);
|
||||
|
||||
const kb = this._keybindingService.lookupKeybinding(this._quickFixActionId);
|
||||
if (kb) {
|
||||
this.title = nls.localize('quickFixWithKb', "Show Fixes ({0})", kb.getLabel());
|
||||
@@ -228,7 +236,7 @@ registerThemingParticipant((theme: IColorTheme, collector: ICssStyleCollector) =
|
||||
const editorLightBulbForegroundColor = theme.getColor(editorLightBulbForeground);
|
||||
if (editorLightBulbForegroundColor) {
|
||||
collector.addRule(`
|
||||
.monaco-editor .contentWidgets .codicon-lightbulb {
|
||||
.monaco-editor .contentWidgets ${Codicon.lightBulb.cssSelector} {
|
||||
color: ${editorLightBulbForegroundColor};
|
||||
}`);
|
||||
}
|
||||
@@ -237,7 +245,7 @@ registerThemingParticipant((theme: IColorTheme, collector: ICssStyleCollector) =
|
||||
const editorLightBulbAutoFixForegroundColor = theme.getColor(editorLightBulbAutoFixForeground);
|
||||
if (editorLightBulbAutoFixForegroundColor) {
|
||||
collector.addRule(`
|
||||
.monaco-editor .contentWidgets .codicon-lightbulb-autofix {
|
||||
.monaco-editor .contentWidgets ${Codicon.lightbulbAutofix.cssSelector} {
|
||||
color: ${editorLightBulbAutoFixForegroundColor};
|
||||
}`);
|
||||
}
|
||||
|
||||
@@ -67,7 +67,7 @@ export class CodeLensContribution implements IEditorContribution {
|
||||
}));
|
||||
this._onModelChange();
|
||||
|
||||
this._styleClassName = hash(this._editor.getId()).toString(16);
|
||||
this._styleClassName = '_' + hash(this._editor.getId()).toString(16);
|
||||
this._styleElement = dom.createStyleSheet(
|
||||
dom.isInShadowDOM(this._editor.getContainerDomNode())
|
||||
? this._editor.getContainerDomNode()
|
||||
|
||||
@@ -5,7 +5,6 @@
|
||||
|
||||
import { binarySearch, coalesceInPlace, equals } from 'vs/base/common/arrays';
|
||||
import { CancellationToken, CancellationTokenSource } from 'vs/base/common/cancellation';
|
||||
import { first, forEach, size } from 'vs/base/common/collections';
|
||||
import { onUnexpectedExternalError } from 'vs/base/common/errors';
|
||||
import { LRUCache } from 'vs/base/common/map';
|
||||
import { commonPrefixLength } from 'vs/base/common/strings';
|
||||
@@ -14,18 +13,21 @@ import { IRange, Range } from 'vs/editor/common/core/range';
|
||||
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 { MovingAverage } from 'vs/base/common/numbers';
|
||||
import { URI } from 'vs/base/common/uri';
|
||||
|
||||
export abstract class TreeElement {
|
||||
|
||||
abstract id: string;
|
||||
abstract children: { [id: string]: TreeElement };
|
||||
abstract children: Map<string, TreeElement>;
|
||||
abstract parent: TreeElement | undefined;
|
||||
|
||||
abstract adopt(newParent: TreeElement): TreeElement;
|
||||
|
||||
remove(): void {
|
||||
if (this.parent) {
|
||||
delete this.parent.children[this.id];
|
||||
this.parent.children.delete(this.id);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -37,13 +39,13 @@ export abstract class TreeElement {
|
||||
candidateId = `${container.id}/${candidate}`;
|
||||
} else {
|
||||
candidateId = `${container.id}/${candidate.name}`;
|
||||
if (container.children[candidateId] !== undefined) {
|
||||
if (container.children.get(candidateId) !== undefined) {
|
||||
candidateId = `${container.id}/${candidate.name}_${candidate.range.startLineNumber}_${candidate.range.startColumn}`;
|
||||
}
|
||||
}
|
||||
|
||||
let id = candidateId;
|
||||
for (let i = 0; container.children[id] !== undefined; i++) {
|
||||
for (let i = 0; container.children.get(id) !== undefined; i++) {
|
||||
id = `${candidateId}_${i}`;
|
||||
}
|
||||
|
||||
@@ -61,8 +63,8 @@ export abstract class TreeElement {
|
||||
if (len < element.id.length) {
|
||||
return undefined;
|
||||
}
|
||||
for (const key in element.children) {
|
||||
let candidate = TreeElement.getElementById(id, element.children[key]);
|
||||
for (const [, child] of element.children) {
|
||||
let candidate = TreeElement.getElementById(id, child);
|
||||
if (candidate) {
|
||||
return candidate;
|
||||
}
|
||||
@@ -72,17 +74,14 @@ export abstract class TreeElement {
|
||||
|
||||
static size(element: TreeElement): number {
|
||||
let res = 1;
|
||||
for (const key in element.children) {
|
||||
res += TreeElement.size(element.children[key]);
|
||||
for (const [, child] of element.children) {
|
||||
res += TreeElement.size(child);
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
static empty(element: TreeElement): boolean {
|
||||
for (const _key in element.children) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
return element.children.size === 0;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -96,7 +95,7 @@ export interface IOutlineMarker {
|
||||
|
||||
export class OutlineElement extends TreeElement {
|
||||
|
||||
children: { [id: string]: OutlineElement; } = Object.create(null);
|
||||
children = new Map<string, OutlineElement>();
|
||||
marker: { count: number, topSev: MarkerSeverity } | undefined;
|
||||
|
||||
constructor(
|
||||
@@ -109,27 +108,31 @@ export class OutlineElement extends TreeElement {
|
||||
|
||||
adopt(parent: TreeElement): OutlineElement {
|
||||
let res = new OutlineElement(this.id, parent, this.symbol);
|
||||
forEach(this.children, entry => res.children[entry.key] = entry.value.adopt(res));
|
||||
for (const [key, value] of this.children) {
|
||||
res.children.set(key, value.adopt(res));
|
||||
}
|
||||
return res;
|
||||
}
|
||||
}
|
||||
|
||||
export class OutlineGroup extends TreeElement {
|
||||
|
||||
children: { [id: string]: OutlineElement; } = Object.create(null);
|
||||
children = new Map<string, OutlineElement>();
|
||||
|
||||
constructor(
|
||||
readonly id: string,
|
||||
public parent: TreeElement | undefined,
|
||||
readonly provider: DocumentSymbolProvider,
|
||||
readonly providerIndex: number,
|
||||
readonly label: string,
|
||||
readonly order: number,
|
||||
) {
|
||||
super();
|
||||
}
|
||||
|
||||
adopt(parent: TreeElement): OutlineGroup {
|
||||
let res = new OutlineGroup(this.id, parent, this.provider, this.providerIndex);
|
||||
forEach(this.children, entry => res.children[entry.key] = entry.value.adopt(res));
|
||||
let res = new OutlineGroup(this.id, parent, this.label, this.order);
|
||||
for (const [key, value] of this.children) {
|
||||
res.children.set(key, value.adopt(res));
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
@@ -137,9 +140,8 @@ export class OutlineGroup extends TreeElement {
|
||||
return position ? this._getItemEnclosingPosition(position, this.children) : undefined;
|
||||
}
|
||||
|
||||
private _getItemEnclosingPosition(position: IPosition, children: { [id: string]: OutlineElement }): OutlineElement | undefined {
|
||||
for (let key in children) {
|
||||
let item = children[key];
|
||||
private _getItemEnclosingPosition(position: IPosition, children: Map<string, OutlineElement>): OutlineElement | undefined {
|
||||
for (const [, item] of children) {
|
||||
if (!item.symbol.range || !Range.containsPosition(item.symbol.range, position)) {
|
||||
continue;
|
||||
}
|
||||
@@ -149,8 +151,8 @@ export class OutlineGroup extends TreeElement {
|
||||
}
|
||||
|
||||
updateMarker(marker: IOutlineMarker[]): void {
|
||||
for (const key in this.children) {
|
||||
this._updateMarker(marker, this.children[key]);
|
||||
for (const [, child] of this.children) {
|
||||
this._updateMarker(marker, child);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -187,8 +189,8 @@ export class OutlineGroup extends TreeElement {
|
||||
// this outline element. This might remove markers from this element and
|
||||
// therefore we remember that we have had markers. That allows us to render
|
||||
// the dot, saying 'this element has children with markers'
|
||||
for (const key in item.children) {
|
||||
this._updateMarker(myMarkers, item.children[key]);
|
||||
for (const [, child] of item.children) {
|
||||
this._updateMarker(myMarkers, child);
|
||||
}
|
||||
|
||||
if (myTopSev) {
|
||||
@@ -202,21 +204,7 @@ export class OutlineGroup extends TreeElement {
|
||||
}
|
||||
}
|
||||
|
||||
class MovingAverage {
|
||||
|
||||
private _n = 1;
|
||||
private _val = 0;
|
||||
|
||||
update(value: number): this {
|
||||
this._val = this._val + (value - this._val) / this._n;
|
||||
this._n += 1;
|
||||
return this;
|
||||
}
|
||||
|
||||
get value(): number {
|
||||
return this._val;
|
||||
}
|
||||
}
|
||||
|
||||
export class OutlineModel extends TreeElement {
|
||||
|
||||
@@ -315,14 +303,14 @@ export class OutlineModel extends TreeElement {
|
||||
private static _create(textModel: ITextModel, token: CancellationToken): Promise<OutlineModel> {
|
||||
|
||||
const cts = new CancellationTokenSource(token);
|
||||
const result = new OutlineModel(textModel);
|
||||
const result = new OutlineModel(textModel.uri);
|
||||
const provider = DocumentSymbolProviderRegistry.ordered(textModel);
|
||||
const promises = provider.map((provider, index) => {
|
||||
|
||||
let id = TreeElement.findId(`provider_${index}`, result);
|
||||
let group = new OutlineGroup(id, result, provider, index);
|
||||
let group = new OutlineGroup(id, result, provider.displayName ?? 'Unknown Outline Provider', index);
|
||||
|
||||
return Promise.resolve(provider.provideDocumentSymbols(result.textModel, cts.token)).then(result => {
|
||||
return Promise.resolve(provider.provideDocumentSymbols(textModel, cts.token)).then(result => {
|
||||
for (const info of result || []) {
|
||||
OutlineModel._makeOutlineElement(info, group);
|
||||
}
|
||||
@@ -332,7 +320,7 @@ export class OutlineModel extends TreeElement {
|
||||
return group;
|
||||
}).then(group => {
|
||||
if (!TreeElement.empty(group)) {
|
||||
result._groups[id] = group;
|
||||
result._groups.set(id, group);
|
||||
} else {
|
||||
group.remove();
|
||||
}
|
||||
@@ -365,7 +353,7 @@ export class OutlineModel extends TreeElement {
|
||||
OutlineModel._makeOutlineElement(childInfo, res);
|
||||
}
|
||||
}
|
||||
container.children[res.id] = res;
|
||||
container.children.set(res.id, res);
|
||||
}
|
||||
|
||||
static get(element: TreeElement | undefined): OutlineModel | undefined {
|
||||
@@ -381,10 +369,10 @@ export class OutlineModel extends TreeElement {
|
||||
readonly id = 'root';
|
||||
readonly parent = undefined;
|
||||
|
||||
protected _groups: { [id: string]: OutlineGroup; } = Object.create(null);
|
||||
children: { [id: string]: OutlineGroup | OutlineElement; } = Object.create(null);
|
||||
protected _groups = new Map<string, OutlineGroup>();
|
||||
children = new Map<string, OutlineGroup | OutlineElement>();
|
||||
|
||||
protected constructor(readonly textModel: ITextModel) {
|
||||
protected constructor(readonly uri: URI) {
|
||||
super();
|
||||
|
||||
this.id = 'root';
|
||||
@@ -392,17 +380,18 @@ export class OutlineModel extends TreeElement {
|
||||
}
|
||||
|
||||
adopt(): OutlineModel {
|
||||
let res = new OutlineModel(this.textModel);
|
||||
forEach(this._groups, entry => res._groups[entry.key] = entry.value.adopt(res));
|
||||
let res = new OutlineModel(this.uri);
|
||||
for (const [key, value] of this._groups) {
|
||||
res._groups.set(key, value.adopt(res));
|
||||
}
|
||||
return res._compact();
|
||||
}
|
||||
|
||||
private _compact(): this {
|
||||
let count = 0;
|
||||
for (const key in this._groups) {
|
||||
let group = this._groups[key];
|
||||
if (first(group.children) === undefined) { // empty
|
||||
delete this._groups[key];
|
||||
for (const [key, group] of this._groups) {
|
||||
if (group.children.size === 0) { // empty
|
||||
this._groups.delete(key);
|
||||
} else {
|
||||
count += 1;
|
||||
}
|
||||
@@ -412,21 +401,20 @@ export class OutlineModel extends TreeElement {
|
||||
this.children = this._groups;
|
||||
} else {
|
||||
// adopt all elements of the first group
|
||||
let group = first(this._groups);
|
||||
for (let key in group!.children) {
|
||||
let child = group!.children[key];
|
||||
let group = Iterable.first(this._groups.values())!;
|
||||
for (let [, child] of group.children) {
|
||||
child.parent = this;
|
||||
this.children[child.id] = child;
|
||||
this.children.set(child.id, child);
|
||||
}
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
merge(other: OutlineModel): boolean {
|
||||
if (this.textModel.uri.toString() !== other.textModel.uri.toString()) {
|
||||
if (this.uri.toString() !== other.uri.toString()) {
|
||||
return false;
|
||||
}
|
||||
if (size(this._groups) !== size(other._groups)) {
|
||||
if (this._groups.size !== other._groups.size) {
|
||||
return false;
|
||||
}
|
||||
this._groups = other._groups;
|
||||
@@ -448,8 +436,7 @@ export class OutlineModel extends TreeElement {
|
||||
}
|
||||
|
||||
let result: OutlineElement | undefined = undefined;
|
||||
for (const key in this._groups) {
|
||||
const group = this._groups[key];
|
||||
for (const [, group] of this._groups) {
|
||||
result = group.getItemEnclosingPosition(position);
|
||||
if (result && (!preferredGroup || preferredGroup === group)) {
|
||||
break;
|
||||
@@ -467,8 +454,8 @@ export class OutlineModel extends TreeElement {
|
||||
// outline element starts for quicker look up
|
||||
marker.sort(Range.compareRangesUsingStarts);
|
||||
|
||||
for (const key in this._groups) {
|
||||
this._groups[key].updateMarker(marker.slice(0));
|
||||
for (const [, group] of this._groups) {
|
||||
group.updateMarker(marker.slice(0));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,7 +7,6 @@ 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 { values } from 'vs/base/common/collections';
|
||||
import { createMatches, FuzzyScore } from 'vs/base/common/filters';
|
||||
import 'vs/css!./media/outlineTree';
|
||||
import 'vs/css!./media/symbol-icons';
|
||||
@@ -24,6 +23,9 @@ import { registerColor, listErrorForeground, listWarningForeground, foreground }
|
||||
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;
|
||||
|
||||
@@ -31,13 +33,29 @@ export class OutlineNavigationLabelProvider implements IKeyboardNavigationLabelP
|
||||
|
||||
getKeyboardNavigationLabel(element: OutlineItem): { toString(): string; } {
|
||||
if (element instanceof OutlineGroup) {
|
||||
return element.provider.displayName || element.id;
|
||||
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; } {
|
||||
@@ -91,7 +109,7 @@ export class OutlineGroupRenderer implements ITreeRenderer<OutlineGroup, FuzzySc
|
||||
|
||||
renderElement(node: ITreeNode<OutlineGroup, FuzzyScore>, index: number, template: OutlineGroupTemplate): void {
|
||||
template.label.set(
|
||||
node.element.provider.displayName || localize('provider', "Outline Provider"),
|
||||
node.element.label,
|
||||
createMatches(node.filterData)
|
||||
);
|
||||
}
|
||||
@@ -290,7 +308,7 @@ export class OutlineFilter implements ITreeFilter<OutlineItem> {
|
||||
let uri: URI | undefined;
|
||||
|
||||
if (outline) {
|
||||
uri = outline.textModel.uri;
|
||||
uri = outline.uri;
|
||||
}
|
||||
|
||||
if (!(element instanceof OutlineElement)) {
|
||||
@@ -313,7 +331,7 @@ export class OutlineItemComparator implements ITreeSorter<OutlineItem> {
|
||||
|
||||
compare(a: OutlineItem, b: OutlineItem): number {
|
||||
if (a instanceof OutlineGroup && b instanceof OutlineGroup) {
|
||||
return a.providerIndex - b.providerIndex;
|
||||
return a.order - b.order;
|
||||
|
||||
} else if (a instanceof OutlineElement && b instanceof OutlineElement) {
|
||||
if (this.type === OutlineSortOrder.ByKind) {
|
||||
@@ -330,11 +348,11 @@ export class OutlineItemComparator implements ITreeSorter<OutlineItem> {
|
||||
|
||||
export class OutlineDataSource implements IDataSource<OutlineModel, OutlineItem> {
|
||||
|
||||
getChildren(element: undefined | OutlineModel | OutlineGroup | OutlineElement): OutlineItem[] {
|
||||
getChildren(element: undefined | OutlineModel | OutlineGroup | OutlineElement) {
|
||||
if (!element) {
|
||||
return [];
|
||||
return Iterable.empty();
|
||||
}
|
||||
return values(element.children);
|
||||
return element.children.values();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -540,168 +558,168 @@ registerThemingParticipant((theme: IColorTheme, collector: ICssStyleCollector) =
|
||||
|
||||
const symbolIconArrayColor = theme.getColor(SYMBOL_ICON_ARRAY_FOREGROUND);
|
||||
if (symbolIconArrayColor) {
|
||||
collector.addRule(`.monaco-workbench .codicon-symbol-array { color: ${symbolIconArrayColor}; }`);
|
||||
collector.addRule(`.monaco-workbench ${Codicon.symbolArray.cssSelector} { color: ${symbolIconArrayColor}; }`);
|
||||
}
|
||||
|
||||
const symbolIconBooleanColor = theme.getColor(SYMBOL_ICON_BOOLEAN_FOREGROUND);
|
||||
if (symbolIconBooleanColor) {
|
||||
collector.addRule(`.monaco-workbench .codicon-symbol-boolean { color: ${symbolIconBooleanColor}; }`);
|
||||
collector.addRule(`.monaco-workbench ${Codicon.symbolBoolean.cssSelector} { color: ${symbolIconBooleanColor}; }`);
|
||||
}
|
||||
|
||||
const symbolIconClassColor = theme.getColor(SYMBOL_ICON_CLASS_FOREGROUND);
|
||||
if (symbolIconClassColor) {
|
||||
collector.addRule(`.monaco-workbench .codicon-symbol-class { color: ${symbolIconClassColor}; }`);
|
||||
collector.addRule(`.monaco-workbench ${Codicon.symbolClass.cssSelector} { color: ${symbolIconClassColor}; }`);
|
||||
}
|
||||
|
||||
const symbolIconMethodColor = theme.getColor(SYMBOL_ICON_METHOD_FOREGROUND);
|
||||
if (symbolIconMethodColor) {
|
||||
collector.addRule(`.monaco-workbench .codicon-symbol-method { color: ${symbolIconMethodColor}; }`);
|
||||
collector.addRule(`.monaco-workbench ${Codicon.symbolMethod.cssSelector} { color: ${symbolIconMethodColor}; }`);
|
||||
}
|
||||
|
||||
const symbolIconColorColor = theme.getColor(SYMBOL_ICON_COLOR_FOREGROUND);
|
||||
if (symbolIconColorColor) {
|
||||
collector.addRule(`.monaco-workbench .codicon-symbol-color { color: ${symbolIconColorColor}; }`);
|
||||
collector.addRule(`.monaco-workbench ${Codicon.symbolColor.cssSelector} { color: ${symbolIconColorColor}; }`);
|
||||
}
|
||||
|
||||
const symbolIconConstantColor = theme.getColor(SYMBOL_ICON_CONSTANT_FOREGROUND);
|
||||
if (symbolIconConstantColor) {
|
||||
collector.addRule(`.monaco-workbench .codicon-symbol-constant { color: ${symbolIconConstantColor}; }`);
|
||||
collector.addRule(`.monaco-workbench ${Codicon.symbolConstant.cssSelector} { color: ${symbolIconConstantColor}; }`);
|
||||
}
|
||||
|
||||
const symbolIconConstructorColor = theme.getColor(SYMBOL_ICON_CONSTRUCTOR_FOREGROUND);
|
||||
if (symbolIconConstructorColor) {
|
||||
collector.addRule(`.monaco-workbench .codicon-symbol-constructor { color: ${symbolIconConstructorColor}; }`);
|
||||
collector.addRule(`.monaco-workbench ${Codicon.symbolConstructor.cssSelector} { color: ${symbolIconConstructorColor}; }`);
|
||||
}
|
||||
|
||||
const symbolIconEnumeratorColor = theme.getColor(SYMBOL_ICON_ENUMERATOR_FOREGROUND);
|
||||
if (symbolIconEnumeratorColor) {
|
||||
collector.addRule(`
|
||||
.monaco-workbench .codicon-symbol-value,.monaco-workbench .codicon-symbol-enum { color: ${symbolIconEnumeratorColor}; }`);
|
||||
.monaco-workbench ${Codicon.symbolValue.cssSelector},.monaco-workbench ${Codicon.symbolEnum.cssSelector} { color: ${symbolIconEnumeratorColor}; }`);
|
||||
}
|
||||
|
||||
const symbolIconEnumeratorMemberColor = theme.getColor(SYMBOL_ICON_ENUMERATOR_MEMBER_FOREGROUND);
|
||||
if (symbolIconEnumeratorMemberColor) {
|
||||
collector.addRule(`.monaco-workbench .codicon-symbol-enum-member { color: ${symbolIconEnumeratorMemberColor}; }`);
|
||||
collector.addRule(`.monaco-workbench ${Codicon.symbolEnumMember.cssSelector} { color: ${symbolIconEnumeratorMemberColor}; }`);
|
||||
}
|
||||
|
||||
const symbolIconEventColor = theme.getColor(SYMBOL_ICON_EVENT_FOREGROUND);
|
||||
if (symbolIconEventColor) {
|
||||
collector.addRule(`.monaco-workbench .codicon-symbol-event { color: ${symbolIconEventColor}; }`);
|
||||
collector.addRule(`.monaco-workbench ${Codicon.symbolEvent.cssSelector} { color: ${symbolIconEventColor}; }`);
|
||||
}
|
||||
|
||||
const symbolIconFieldColor = theme.getColor(SYMBOL_ICON_FIELD_FOREGROUND);
|
||||
if (symbolIconFieldColor) {
|
||||
collector.addRule(`.monaco-workbench .codicon-symbol-field { color: ${symbolIconFieldColor}; }`);
|
||||
collector.addRule(`.monaco-workbench ${Codicon.symbolField.cssSelector} { color: ${symbolIconFieldColor}; }`);
|
||||
}
|
||||
|
||||
const symbolIconFileColor = theme.getColor(SYMBOL_ICON_FILE_FOREGROUND);
|
||||
if (symbolIconFileColor) {
|
||||
collector.addRule(`.monaco-workbench .codicon-symbol-file { color: ${symbolIconFileColor}; }`);
|
||||
collector.addRule(`.monaco-workbench ${Codicon.symbolFile.cssSelector} { color: ${symbolIconFileColor}; }`);
|
||||
}
|
||||
|
||||
const symbolIconFolderColor = theme.getColor(SYMBOL_ICON_FOLDER_FOREGROUND);
|
||||
if (symbolIconFolderColor) {
|
||||
collector.addRule(`.monaco-workbench .codicon-symbol-folder { color: ${symbolIconFolderColor}; }`);
|
||||
collector.addRule(`.monaco-workbench ${Codicon.symbolFolder.cssSelector} { color: ${symbolIconFolderColor}; }`);
|
||||
}
|
||||
|
||||
const symbolIconFunctionColor = theme.getColor(SYMBOL_ICON_FUNCTION_FOREGROUND);
|
||||
if (symbolIconFunctionColor) {
|
||||
collector.addRule(`.monaco-workbench .codicon-symbol-function { color: ${symbolIconFunctionColor}; }`);
|
||||
collector.addRule(`.monaco-workbench ${Codicon.symbolFunction.cssSelector} { color: ${symbolIconFunctionColor}; }`);
|
||||
}
|
||||
|
||||
const symbolIconInterfaceColor = theme.getColor(SYMBOL_ICON_INTERFACE_FOREGROUND);
|
||||
if (symbolIconInterfaceColor) {
|
||||
collector.addRule(`.monaco-workbench .codicon-symbol-interface { color: ${symbolIconInterfaceColor}; }`);
|
||||
collector.addRule(`.monaco-workbench ${Codicon.symbolInterface.cssSelector} { color: ${symbolIconInterfaceColor}; }`);
|
||||
}
|
||||
|
||||
const symbolIconKeyColor = theme.getColor(SYMBOL_ICON_KEY_FOREGROUND);
|
||||
if (symbolIconKeyColor) {
|
||||
collector.addRule(`.monaco-workbench .codicon-symbol-key { color: ${symbolIconKeyColor}; }`);
|
||||
collector.addRule(`.monaco-workbench ${Codicon.symbolKey.cssSelector} { color: ${symbolIconKeyColor}; }`);
|
||||
}
|
||||
|
||||
const symbolIconKeywordColor = theme.getColor(SYMBOL_ICON_KEYWORD_FOREGROUND);
|
||||
if (symbolIconKeywordColor) {
|
||||
collector.addRule(`.monaco-workbench .codicon-symbol-keyword { color: ${symbolIconKeywordColor}; }`);
|
||||
collector.addRule(`.monaco-workbench ${Codicon.symbolKeyword.cssSelector} { color: ${symbolIconKeywordColor}; }`);
|
||||
}
|
||||
|
||||
const symbolIconModuleColor = theme.getColor(SYMBOL_ICON_MODULE_FOREGROUND);
|
||||
if (symbolIconModuleColor) {
|
||||
collector.addRule(`.monaco-workbench .codicon-symbol-module { color: ${symbolIconModuleColor}; }`);
|
||||
collector.addRule(`.monaco-workbench ${Codicon.symbolModule.cssSelector} { color: ${symbolIconModuleColor}; }`);
|
||||
}
|
||||
|
||||
const outlineNamespaceColor = theme.getColor(SYMBOL_ICON_NAMESPACE_FOREGROUND);
|
||||
if (outlineNamespaceColor) {
|
||||
collector.addRule(`.monaco-workbench .codicon-symbol-namespace { color: ${outlineNamespaceColor}; }`);
|
||||
collector.addRule(`.monaco-workbench ${Codicon.symbolNamespace.cssSelector} { color: ${outlineNamespaceColor}; }`);
|
||||
}
|
||||
|
||||
const symbolIconNullColor = theme.getColor(SYMBOL_ICON_NULL_FOREGROUND);
|
||||
if (symbolIconNullColor) {
|
||||
collector.addRule(`.monaco-workbench .codicon-symbol-null { color: ${symbolIconNullColor}; }`);
|
||||
collector.addRule(`.monaco-workbench ${Codicon.symbolNull.cssSelector} { color: ${symbolIconNullColor}; }`);
|
||||
}
|
||||
|
||||
const symbolIconNumberColor = theme.getColor(SYMBOL_ICON_NUMBER_FOREGROUND);
|
||||
if (symbolIconNumberColor) {
|
||||
collector.addRule(`.monaco-workbench .codicon-symbol-number { color: ${symbolIconNumberColor}; }`);
|
||||
collector.addRule(`.monaco-workbench ${Codicon.symbolNumber.cssSelector} { color: ${symbolIconNumberColor}; }`);
|
||||
}
|
||||
|
||||
const symbolIconObjectColor = theme.getColor(SYMBOL_ICON_OBJECT_FOREGROUND);
|
||||
if (symbolIconObjectColor) {
|
||||
collector.addRule(`.monaco-workbench .codicon-symbol-object { color: ${symbolIconObjectColor}; }`);
|
||||
collector.addRule(`.monaco-workbench ${Codicon.symbolObject.cssSelector} { color: ${symbolIconObjectColor}; }`);
|
||||
}
|
||||
|
||||
const symbolIconOperatorColor = theme.getColor(SYMBOL_ICON_OPERATOR_FOREGROUND);
|
||||
if (symbolIconOperatorColor) {
|
||||
collector.addRule(`.monaco-workbench .codicon-symbol-operator { color: ${symbolIconOperatorColor}; }`);
|
||||
collector.addRule(`.monaco-workbench ${Codicon.symbolOperator.cssSelector} { color: ${symbolIconOperatorColor}; }`);
|
||||
}
|
||||
|
||||
const symbolIconPackageColor = theme.getColor(SYMBOL_ICON_PACKAGE_FOREGROUND);
|
||||
if (symbolIconPackageColor) {
|
||||
collector.addRule(`.monaco-workbench .codicon-symbol-package { color: ${symbolIconPackageColor}; }`);
|
||||
collector.addRule(`.monaco-workbench ${Codicon.symbolPackage.cssSelector} { color: ${symbolIconPackageColor}; }`);
|
||||
}
|
||||
|
||||
const symbolIconPropertyColor = theme.getColor(SYMBOL_ICON_PROPERTY_FOREGROUND);
|
||||
if (symbolIconPropertyColor) {
|
||||
collector.addRule(`.monaco-workbench .codicon-symbol-property { color: ${symbolIconPropertyColor}; }`);
|
||||
collector.addRule(`.monaco-workbench ${Codicon.symbolProperty.cssSelector} { color: ${symbolIconPropertyColor}; }`);
|
||||
}
|
||||
|
||||
const symbolIconReferenceColor = theme.getColor(SYMBOL_ICON_REFERENCE_FOREGROUND);
|
||||
if (symbolIconReferenceColor) {
|
||||
collector.addRule(`.monaco-workbench .codicon-symbol-reference { color: ${symbolIconReferenceColor}; }`);
|
||||
collector.addRule(`.monaco-workbench ${Codicon.symbolReference.cssSelector} { color: ${symbolIconReferenceColor}; }`);
|
||||
}
|
||||
|
||||
const symbolIconSnippetColor = theme.getColor(SYMBOL_ICON_SNIPPET_FOREGROUND);
|
||||
if (symbolIconSnippetColor) {
|
||||
collector.addRule(`.monaco-workbench .codicon-symbol-snippet { color: ${symbolIconSnippetColor}; }`);
|
||||
collector.addRule(`.monaco-workbench ${Codicon.symbolSnippet.cssSelector} { color: ${symbolIconSnippetColor}; }`);
|
||||
}
|
||||
|
||||
const symbolIconStringColor = theme.getColor(SYMBOL_ICON_STRING_FOREGROUND);
|
||||
if (symbolIconStringColor) {
|
||||
collector.addRule(`.monaco-workbench .codicon-symbol-string { color: ${symbolIconStringColor}; }`);
|
||||
collector.addRule(`.monaco-workbench ${Codicon.symbolString.cssSelector} { color: ${symbolIconStringColor}; }`);
|
||||
}
|
||||
|
||||
const symbolIconStructColor = theme.getColor(SYMBOL_ICON_STRUCT_FOREGROUND);
|
||||
if (symbolIconStructColor) {
|
||||
collector.addRule(`.monaco-workbench .codicon-symbol-struct { color: ${symbolIconStructColor}; }`);
|
||||
collector.addRule(`.monaco-workbench ${Codicon.symbolStruct.cssSelector} { color: ${symbolIconStructColor}; }`);
|
||||
}
|
||||
|
||||
const symbolIconTextColor = theme.getColor(SYMBOL_ICON_TEXT_FOREGROUND);
|
||||
if (symbolIconTextColor) {
|
||||
collector.addRule(`.monaco-workbench .codicon-symbol-text { color: ${symbolIconTextColor}; }`);
|
||||
collector.addRule(`.monaco-workbench ${Codicon.symbolText.cssSelector} { color: ${symbolIconTextColor}; }`);
|
||||
}
|
||||
|
||||
const symbolIconTypeParameterColor = theme.getColor(SYMBOL_ICON_TYPEPARAMETER_FOREGROUND);
|
||||
if (symbolIconTypeParameterColor) {
|
||||
collector.addRule(`.monaco-workbench .codicon-symbol-type-parameter { color: ${symbolIconTypeParameterColor}; }`);
|
||||
collector.addRule(`.monaco-workbench ${Codicon.symbolTypeParameter.cssSelector} { color: ${symbolIconTypeParameterColor}; }`);
|
||||
}
|
||||
|
||||
const symbolIconUnitColor = theme.getColor(SYMBOL_ICON_UNIT_FOREGROUND);
|
||||
if (symbolIconUnitColor) {
|
||||
collector.addRule(`.monaco-workbench .codicon-symbol-unit { color: ${symbolIconUnitColor}; }`);
|
||||
collector.addRule(`.monaco-workbench ${Codicon.symbolUnit.cssSelector} { color: ${symbolIconUnitColor}; }`);
|
||||
}
|
||||
|
||||
const symbolIconVariableColor = theme.getColor(SYMBOL_ICON_VARIABLE_FOREGROUND);
|
||||
if (symbolIconVariableColor) {
|
||||
collector.addRule(`.monaco-workbench .codicon-symbol-variable { color: ${symbolIconVariableColor}; }`);
|
||||
collector.addRule(`.monaco-workbench ${Codicon.symbolVariable.cssSelector} { color: ${symbolIconVariableColor}; }`);
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
@@ -93,9 +93,9 @@ suite('OutlineModel', function () {
|
||||
let e2 = new OutlineElement('foo3', null!, fakeSymbolInformation(new Range(6, 1, 10, 10)));
|
||||
|
||||
let group = new OutlineGroup('group', null!, null!, 1);
|
||||
group.children[e0.id] = e0;
|
||||
group.children[e1.id] = e1;
|
||||
group.children[e2.id] = e2;
|
||||
group.children.set(e0.id, e0);
|
||||
group.children.set(e1.id, e1);
|
||||
group.children.set(e2.id, e2);
|
||||
|
||||
const data = [fakeMarker(new Range(6, 1, 6, 7)), fakeMarker(new Range(1, 1, 1, 4)), fakeMarker(new Range(10, 2, 14, 1))];
|
||||
data.sort(Range.compareRangesUsingStarts); // model does this
|
||||
@@ -119,9 +119,9 @@ suite('OutlineModel', function () {
|
||||
let c2 = new OutlineElement('A/C', null!, fakeSymbolInformation(new Range(6, 4, 9, 4)));
|
||||
|
||||
let group = new OutlineGroup('group', null!, null!, 1);
|
||||
group.children[p.id] = p;
|
||||
p.children[c1.id] = c1;
|
||||
p.children[c2.id] = c2;
|
||||
group.children.set(p.id, p);
|
||||
p.children.set(c1.id, c1);
|
||||
p.children.set(c2.id, c2);
|
||||
|
||||
let data = [
|
||||
fakeMarker(new Range(2, 4, 5, 4))
|
||||
@@ -162,13 +162,13 @@ suite('OutlineModel', function () {
|
||||
this._groups = this.children as any;
|
||||
}
|
||||
};
|
||||
model.children['g1'] = new OutlineGroup('g1', model, null!, 1);
|
||||
model.children['g1'].children['c1'] = new OutlineElement('c1', model.children['g1'], fakeSymbolInformation(new Range(1, 1, 11, 1)));
|
||||
model.children.set('g1', new OutlineGroup('g1', model, null!, 1));
|
||||
model.children.get('g1')!.children.set('c1', new OutlineElement('c1', model.children.get('g1')!, fakeSymbolInformation(new Range(1, 1, 11, 1))));
|
||||
|
||||
model.children['g2'] = new OutlineGroup('g2', model, null!, 1);
|
||||
model.children['g2'].children['c2'] = new OutlineElement('c2', model.children['g2'], fakeSymbolInformation(new Range(1, 1, 7, 1)));
|
||||
model.children['g2'].children['c2'].children['c2.1'] = new OutlineElement('c2.1', model.children['g2'].children['c2'], fakeSymbolInformation(new Range(1, 3, 2, 19)));
|
||||
model.children['g2'].children['c2'].children['c2.2'] = new OutlineElement('c2.2', model.children['g2'].children['c2'], fakeSymbolInformation(new Range(4, 1, 6, 10)));
|
||||
model.children.set('g2', new OutlineGroup('g2', model, null!, 1));
|
||||
model.children.get('g2')!.children.set('c2', new OutlineElement('c2', model.children.get('g2')!, fakeSymbolInformation(new Range(1, 1, 7, 1))));
|
||||
model.children.get('g2')!.children.get('c2')!.children.set('c2.1', new OutlineElement('c2.1', model.children.get('g2')!.children.get('c2')!, fakeSymbolInformation(new Range(1, 3, 2, 19))));
|
||||
model.children.get('g2')!.children.get('c2')!.children.set('c2.2', new OutlineElement('c2.2', model.children.get('g2')!.children.get('c2')!, fakeSymbolInformation(new Range(4, 1, 6, 10))));
|
||||
|
||||
model.readyForTesting();
|
||||
|
||||
@@ -179,9 +179,9 @@ suite('OutlineModel', function () {
|
||||
|
||||
model.updateMarker(data);
|
||||
|
||||
assert.equal(model.children['g1']!.children['c1'].marker!.count, 2);
|
||||
assert.equal(model.children['g2']!.children['c2'].children['c2.1'].marker!.count, 1);
|
||||
assert.equal(model.children['g2']!.children['c2'].children['c2.2'].marker!.count, 1);
|
||||
assert.equal(model.children.get('g1')!.children.get('c1')!.marker!.count, 2);
|
||||
assert.equal(model.children.get('g2')!.children.get('c2')!.children.get('c2.1')!.marker!.count, 1);
|
||||
assert.equal(model.children.get('g2')!.children.get('c2')!.children.get('c2.2')!.marker!.count, 1);
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
@@ -27,6 +27,7 @@ import { IStorageService, StorageScope } from 'vs/platform/storage/common/storag
|
||||
import { IThemeService } from 'vs/platform/theme/common/themeService';
|
||||
import { INotificationService } from 'vs/platform/notification/common/notification';
|
||||
import { EditorOption } from 'vs/editor/common/config/editorOptions';
|
||||
import { IStorageKeysSyncRegistryService } from 'vs/platform/userDataSync/common/storageKeys';
|
||||
|
||||
const SEARCH_STRING_MAX_LENGTH = 524288;
|
||||
|
||||
@@ -66,6 +67,7 @@ export interface IFindStartOptions {
|
||||
shouldFocus: FindStartFocusAction;
|
||||
shouldAnimate: boolean;
|
||||
updateSearchScope: boolean;
|
||||
loop: boolean;
|
||||
}
|
||||
|
||||
export class CommonFindController extends Disposable implements IEditorContribution {
|
||||
@@ -125,7 +127,8 @@ export class CommonFindController extends Disposable implements IEditorContribut
|
||||
seedSearchStringFromGlobalClipboard: false,
|
||||
shouldFocus: FindStartFocusAction.NoFocusChange,
|
||||
shouldAnimate: false,
|
||||
updateSearchScope: false
|
||||
updateSearchScope: false,
|
||||
loop: this._editor.getOption(EditorOption.find).loop
|
||||
});
|
||||
}
|
||||
}));
|
||||
@@ -296,6 +299,8 @@ export class CommonFindController extends Disposable implements IEditorContribut
|
||||
}
|
||||
}
|
||||
|
||||
stateChanges.loop = opts.loop;
|
||||
|
||||
this._state.change(stateChanges, false);
|
||||
|
||||
if (!this._model) {
|
||||
@@ -383,6 +388,7 @@ export class FindController extends CommonFindController implements IFindControl
|
||||
@IThemeService private readonly _themeService: IThemeService,
|
||||
@INotificationService private readonly _notificationService: INotificationService,
|
||||
@IStorageService _storageService: IStorageService,
|
||||
@IStorageKeysSyncRegistryService private readonly _storageKeysSyncRegistryService: IStorageKeysSyncRegistryService,
|
||||
@optional(IClipboardService) clipboardService: IClipboardService,
|
||||
) {
|
||||
super(editor, _contextKeyService, _storageService, clipboardService);
|
||||
@@ -437,7 +443,7 @@ export class FindController extends CommonFindController implements IFindControl
|
||||
}
|
||||
|
||||
private _createFindWidget() {
|
||||
this._widget = this._register(new FindWidget(this._editor, this, this._state, this._contextViewService, this._keybindingService, this._contextKeyService, this._themeService, this._storageService, this._notificationService));
|
||||
this._widget = this._register(new FindWidget(this._editor, this, this._state, this._contextViewService, this._keybindingService, this._contextKeyService, this._themeService, this._storageService, this._notificationService, this._storageKeysSyncRegistryService));
|
||||
this._findOptionsWidget = this._register(new FindOptionsWidget(this._editor, this._state, this._keybindingService, this._themeService));
|
||||
}
|
||||
}
|
||||
@@ -473,7 +479,8 @@ export class StartFindAction extends EditorAction {
|
||||
seedSearchStringFromGlobalClipboard: editor.getOption(EditorOption.find).globalFindClipboard,
|
||||
shouldFocus: FindStartFocusAction.FocusFindInput,
|
||||
shouldAnimate: true,
|
||||
updateSearchScope: false
|
||||
updateSearchScope: false,
|
||||
loop: editor.getOption(EditorOption.find).loop
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -507,7 +514,8 @@ export class StartFindWithSelectionAction extends EditorAction {
|
||||
seedSearchStringFromGlobalClipboard: false,
|
||||
shouldFocus: FindStartFocusAction.NoFocusChange,
|
||||
shouldAnimate: true,
|
||||
updateSearchScope: false
|
||||
updateSearchScope: false,
|
||||
loop: editor.getOption(EditorOption.find).loop
|
||||
});
|
||||
|
||||
controller.setGlobalBufferTerm(controller.getState().searchString);
|
||||
@@ -524,7 +532,8 @@ export abstract class MatchFindAction extends EditorAction {
|
||||
seedSearchStringFromGlobalClipboard: true,
|
||||
shouldFocus: FindStartFocusAction.NoFocusChange,
|
||||
shouldAnimate: true,
|
||||
updateSearchScope: false
|
||||
updateSearchScope: false,
|
||||
loop: editor.getOption(EditorOption.find).loop
|
||||
});
|
||||
this._run(controller);
|
||||
}
|
||||
@@ -636,7 +645,8 @@ export abstract class SelectionMatchFindAction extends EditorAction {
|
||||
seedSearchStringFromGlobalClipboard: false,
|
||||
shouldFocus: FindStartFocusAction.NoFocusChange,
|
||||
shouldAnimate: true,
|
||||
updateSearchScope: false
|
||||
updateSearchScope: false,
|
||||
loop: editor.getOption(EditorOption.find).loop
|
||||
});
|
||||
this._run(controller);
|
||||
}
|
||||
@@ -741,7 +751,8 @@ export class StartFindReplaceAction extends EditorAction {
|
||||
seedSearchStringFromGlobalClipboard: editor.getOption(EditorOption.find).seedSearchStringFromSelection,
|
||||
shouldFocus: shouldFocus,
|
||||
shouldAnimate: true,
|
||||
updateSearchScope: false
|
||||
updateSearchScope: false,
|
||||
loop: editor.getOption(EditorOption.find).loop
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -86,7 +86,8 @@ export class FindDecorations implements IDisposable {
|
||||
return this._getDecorationIndex(candidate.id);
|
||||
}
|
||||
}
|
||||
return 1;
|
||||
// We don't know the current match position, so returns zero to show '?' in find widget
|
||||
return 0;
|
||||
}
|
||||
|
||||
public setCurrentFindMatch(nextMatch: Range | null): number {
|
||||
|
||||
@@ -251,6 +251,9 @@ export class FindModelBoundToEditorModel {
|
||||
}
|
||||
|
||||
private _moveToPrevMatch(before: Position, isRecursed: boolean = false): void {
|
||||
if (!this._state.canNavigateBack()) {
|
||||
return;
|
||||
}
|
||||
if (this._decorations.getCount() < MATCHES_LIMIT) {
|
||||
let prevMatchRange = this._decorations.matchBeforePosition(before);
|
||||
|
||||
@@ -336,6 +339,9 @@ export class FindModelBoundToEditorModel {
|
||||
}
|
||||
|
||||
private _moveToNextMatch(after: Position): void {
|
||||
if (!this._state.canNavigateForward()) {
|
||||
return;
|
||||
}
|
||||
if (this._decorations.getCount() < MATCHES_LIMIT) {
|
||||
let nextMatchRange = this._decorations.matchAfterPosition(after);
|
||||
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
import { Emitter, Event } from 'vs/base/common/event';
|
||||
import { Disposable } from 'vs/base/common/lifecycle';
|
||||
import { Range } from 'vs/editor/common/core/range';
|
||||
import { MATCHES_LIMIT } from './findModel';
|
||||
|
||||
export interface FindReplaceStateChangedEvent {
|
||||
moveCursor: boolean;
|
||||
@@ -23,6 +24,7 @@ export interface FindReplaceStateChangedEvent {
|
||||
matchesPosition: boolean;
|
||||
matchesCount: boolean;
|
||||
currentMatch: boolean;
|
||||
loop: boolean;
|
||||
}
|
||||
|
||||
export const enum FindOptionOverride {
|
||||
@@ -45,6 +47,7 @@ export interface INewFindReplaceState {
|
||||
preserveCase?: boolean;
|
||||
preserveCaseOverride?: FindOptionOverride;
|
||||
searchScope?: Range | null;
|
||||
loop?: boolean;
|
||||
}
|
||||
|
||||
function effectiveOptionValue(override: FindOptionOverride, value: boolean): boolean {
|
||||
@@ -74,6 +77,7 @@ export class FindReplaceState extends Disposable {
|
||||
private _matchesPosition: number;
|
||||
private _matchesCount: number;
|
||||
private _currentMatch: Range | null;
|
||||
private _loop: boolean;
|
||||
private readonly _onFindReplaceStateChange = this._register(new Emitter<FindReplaceStateChangedEvent>());
|
||||
|
||||
public get searchString(): string { return this._searchString; }
|
||||
@@ -114,6 +118,7 @@ export class FindReplaceState extends Disposable {
|
||||
this._matchesPosition = 0;
|
||||
this._matchesCount = 0;
|
||||
this._currentMatch = null;
|
||||
this._loop = true;
|
||||
}
|
||||
|
||||
public changeMatchInfo(matchesPosition: number, matchesCount: number, currentMatch: Range | undefined): void {
|
||||
@@ -131,7 +136,8 @@ export class FindReplaceState extends Disposable {
|
||||
searchScope: false,
|
||||
matchesPosition: false,
|
||||
matchesCount: false,
|
||||
currentMatch: false
|
||||
currentMatch: false,
|
||||
loop: false
|
||||
};
|
||||
let somethingChanged = false;
|
||||
|
||||
@@ -181,7 +187,8 @@ export class FindReplaceState extends Disposable {
|
||||
searchScope: false,
|
||||
matchesPosition: false,
|
||||
matchesCount: false,
|
||||
currentMatch: false
|
||||
currentMatch: false,
|
||||
loop: false
|
||||
};
|
||||
let somethingChanged = false;
|
||||
|
||||
@@ -237,7 +244,13 @@ export class FindReplaceState extends Disposable {
|
||||
somethingChanged = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (typeof newState.loop !== 'undefined') {
|
||||
if (this._loop !== newState.loop) {
|
||||
this._loop = newState.loop;
|
||||
changeEvent.loop = true;
|
||||
somethingChanged = true;
|
||||
}
|
||||
}
|
||||
// Overrides get set when they explicitly come in and get reset anytime something else changes
|
||||
this._isRegexOverride = (typeof newState.isRegexOverride !== 'undefined' ? newState.isRegexOverride : FindOptionOverride.NotSet);
|
||||
this._wholeWordOverride = (typeof newState.wholeWordOverride !== 'undefined' ? newState.wholeWordOverride : FindOptionOverride.NotSet);
|
||||
@@ -266,4 +279,17 @@ export class FindReplaceState extends Disposable {
|
||||
this._onFindReplaceStateChange.fire(changeEvent);
|
||||
}
|
||||
}
|
||||
|
||||
public canNavigateBack(): boolean {
|
||||
return this.canNavigateInLoop() || (this.matchesPosition !== 1);
|
||||
}
|
||||
|
||||
public canNavigateForward(): boolean {
|
||||
return this.canNavigateInLoop() || (this.matchesPosition < this.matchesCount);
|
||||
}
|
||||
|
||||
private canNavigateInLoop(): boolean {
|
||||
return this._loop || (this.matchesCount >= MATCHES_LIMIT);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -36,6 +36,18 @@ import { ContextScopedFindInput, ContextScopedReplaceInput } from 'vs/platform/b
|
||||
import { AccessibilitySupport } from 'vs/platform/accessibility/common/accessibility';
|
||||
import { IStorageService, StorageScope } from 'vs/platform/storage/common/storage';
|
||||
import { INotificationService } from 'vs/platform/notification/common/notification';
|
||||
import { IStorageKeysSyncRegistryService } from 'vs/platform/userDataSync/common/storageKeys';
|
||||
import { Codicon, registerIcon } from 'vs/base/common/codicons';
|
||||
|
||||
const findSelectionIcon = registerIcon('find-selection', Codicon.selection);
|
||||
const findCollapsedIcon = registerIcon('find-collapsed', Codicon.chevronRight);
|
||||
const findExpandedIcon = registerIcon('find-expanded', Codicon.chevronDown);
|
||||
|
||||
export const findCloseIcon = registerIcon('find-close', Codicon.close);
|
||||
export const findReplaceIcon = registerIcon('find-replace', Codicon.replace);
|
||||
export const findReplaceAllIcon = registerIcon('find-replace-all', Codicon.replaceAll);
|
||||
export const findPreviousMatchIcon = registerIcon('find-previous-match', Codicon.arrowUp);
|
||||
export const findNextMatchIcon = registerIcon('find-next-match', Codicon.arrowDown);
|
||||
|
||||
export interface IFindController {
|
||||
replace(): void;
|
||||
@@ -152,6 +164,7 @@ export class FindWidget extends Widget implements IOverlayWidget, IHorizontalSas
|
||||
themeService: IThemeService,
|
||||
storageService: IStorageService,
|
||||
notificationService: INotificationService,
|
||||
storageKeysSyncRegistryService: IStorageKeysSyncRegistryService
|
||||
) {
|
||||
super();
|
||||
this._codeEditor = codeEditor;
|
||||
@@ -163,6 +176,7 @@ export class FindWidget extends Widget implements IOverlayWidget, IHorizontalSas
|
||||
this._storageService = storageService;
|
||||
this._notificationService = notificationService;
|
||||
|
||||
storageKeysSyncRegistryService.registerStorageKey({ key: ctrlEnterReplaceAllWarningPromptedKey, version: 1 });
|
||||
this._ctrlEnterReplaceAllWarningPrompted = !!storageService.getBoolean(ctrlEnterReplaceAllWarningPromptedKey, StorageScope.GLOBAL);
|
||||
|
||||
this._isVisible = false;
|
||||
@@ -360,6 +374,9 @@ export class FindWidget extends Widget implements IOverlayWidget, IHorizontalSas
|
||||
if (e.updateHistory) {
|
||||
this._delayedUpdateHistory();
|
||||
}
|
||||
if (e.loop) {
|
||||
this._updateButtons();
|
||||
}
|
||||
}
|
||||
|
||||
private _delayedUpdateHistory() {
|
||||
@@ -405,7 +422,7 @@ export class FindWidget extends Widget implements IOverlayWidget, IHorizontalSas
|
||||
|
||||
this._matchesCount.appendChild(document.createTextNode(label));
|
||||
|
||||
alertFn(this._getAriaLabel(label, this._state.currentMatch, this._state.searchString), true);
|
||||
alertFn(this._getAriaLabel(label, this._state.currentMatch, this._state.searchString));
|
||||
MAX_MATCHES_COUNT_WIDTH = Math.max(MAX_MATCHES_COUNT_WIDTH, this._matchesCount.clientWidth);
|
||||
}
|
||||
|
||||
@@ -455,14 +472,12 @@ export class FindWidget extends Widget implements IOverlayWidget, IHorizontalSas
|
||||
|
||||
let findInputIsNonEmpty = (this._state.searchString.length > 0);
|
||||
let matchesCount = this._state.matchesCount ? true : false;
|
||||
this._prevBtn.setEnabled(this._isVisible && findInputIsNonEmpty && matchesCount);
|
||||
this._nextBtn.setEnabled(this._isVisible && findInputIsNonEmpty && matchesCount);
|
||||
this._prevBtn.setEnabled(this._isVisible && findInputIsNonEmpty && matchesCount && this._state.canNavigateBack());
|
||||
this._nextBtn.setEnabled(this._isVisible && findInputIsNonEmpty && matchesCount && this._state.canNavigateForward());
|
||||
this._replaceBtn.setEnabled(this._isVisible && this._isReplaceVisible && findInputIsNonEmpty);
|
||||
this._replaceAllBtn.setEnabled(this._isVisible && this._isReplaceVisible && findInputIsNonEmpty);
|
||||
|
||||
dom.toggleClass(this._domNode, 'replaceToggled', this._isReplaceVisible);
|
||||
this._toggleReplaceBtn.toggleClass('codicon-chevron-right', !this._isReplaceVisible);
|
||||
this._toggleReplaceBtn.toggleClass('codicon-chevron-down', this._isReplaceVisible);
|
||||
this._toggleReplaceBtn.setExpanded(this._isReplaceVisible);
|
||||
|
||||
let canReplace = !this._codeEditor.getOption(EditorOption.readOnly);
|
||||
@@ -984,7 +999,7 @@ export class FindWidget extends Widget implements IOverlayWidget, IHorizontalSas
|
||||
// Previous button
|
||||
this._prevBtn = this._register(new SimpleButton({
|
||||
label: NLS_PREVIOUS_MATCH_BTN_LABEL + this._keybindingLabelFor(FIND_IDS.PreviousMatchFindAction),
|
||||
className: 'codicon codicon-arrow-up',
|
||||
className: findPreviousMatchIcon.classNames,
|
||||
onTrigger: () => {
|
||||
this._codeEditor.getAction(FIND_IDS.PreviousMatchFindAction).run().then(undefined, onUnexpectedError);
|
||||
}
|
||||
@@ -993,7 +1008,7 @@ export class FindWidget extends Widget implements IOverlayWidget, IHorizontalSas
|
||||
// Next button
|
||||
this._nextBtn = this._register(new SimpleButton({
|
||||
label: NLS_NEXT_MATCH_BTN_LABEL + this._keybindingLabelFor(FIND_IDS.NextMatchFindAction),
|
||||
className: 'codicon codicon-arrow-down',
|
||||
className: findNextMatchIcon.classNames,
|
||||
onTrigger: () => {
|
||||
this._codeEditor.getAction(FIND_IDS.NextMatchFindAction).run().then(undefined, onUnexpectedError);
|
||||
}
|
||||
@@ -1011,7 +1026,7 @@ export class FindWidget extends Widget implements IOverlayWidget, IHorizontalSas
|
||||
|
||||
// Toggle selection button
|
||||
this._toggleSelectionFind = this._register(new Checkbox({
|
||||
actionClassName: 'codicon codicon-selection',
|
||||
icon: findSelectionIcon,
|
||||
title: NLS_TOGGLE_SELECTION_FIND_TITLE + this._keybindingLabelFor(FIND_IDS.ToggleSearchScopeCommand),
|
||||
isChecked: false
|
||||
}));
|
||||
@@ -1037,7 +1052,7 @@ export class FindWidget extends Widget implements IOverlayWidget, IHorizontalSas
|
||||
// Close button
|
||||
this._closeBtn = this._register(new SimpleButton({
|
||||
label: NLS_CLOSE_BTN_LABEL + this._keybindingLabelFor(FIND_IDS.CloseFindWidgetCommand),
|
||||
className: 'codicon codicon-close',
|
||||
className: findCloseIcon.classNames,
|
||||
onTrigger: () => {
|
||||
this._state.change({ isRevealed: false, searchScope: null }, false);
|
||||
},
|
||||
@@ -1100,7 +1115,7 @@ export class FindWidget extends Widget implements IOverlayWidget, IHorizontalSas
|
||||
// Replace one button
|
||||
this._replaceBtn = this._register(new SimpleButton({
|
||||
label: NLS_REPLACE_BTN_LABEL + this._keybindingLabelFor(FIND_IDS.ReplaceOneAction),
|
||||
className: 'codicon codicon-replace',
|
||||
className: findReplaceIcon.classNames,
|
||||
onTrigger: () => {
|
||||
this._controller.replace();
|
||||
},
|
||||
@@ -1115,7 +1130,7 @@ export class FindWidget extends Widget implements IOverlayWidget, IHorizontalSas
|
||||
// Replace all button
|
||||
this._replaceAllBtn = this._register(new SimpleButton({
|
||||
label: NLS_REPLACE_ALL_BTN_LABEL + this._keybindingLabelFor(FIND_IDS.ReplaceAllAction),
|
||||
className: 'codicon codicon-replace-all',
|
||||
className: findReplaceAllIcon.classNames,
|
||||
onTrigger: () => {
|
||||
this._controller.replaceAll();
|
||||
}
|
||||
@@ -1145,8 +1160,6 @@ export class FindWidget extends Widget implements IOverlayWidget, IHorizontalSas
|
||||
this._showViewZone();
|
||||
}
|
||||
}));
|
||||
this._toggleReplaceBtn.toggleClass('codicon-chevron-down', this._isReplaceVisible);
|
||||
this._toggleReplaceBtn.toggleClass('codicon-chevron-right', !this._isReplaceVisible);
|
||||
this._toggleReplaceBtn.setExpanded(this._isReplaceVisible);
|
||||
|
||||
// Widget
|
||||
@@ -1289,10 +1302,13 @@ export class SimpleButton extends Widget {
|
||||
|
||||
public setExpanded(expanded: boolean): void {
|
||||
this._domNode.setAttribute('aria-expanded', String(!!expanded));
|
||||
}
|
||||
|
||||
public toggleClass(className: string, shouldHaveIt: boolean): void {
|
||||
dom.toggleClass(this._domNode, className, shouldHaveIt);
|
||||
if (expanded) {
|
||||
dom.removeClasses(this._domNode, findCollapsedIcon.classNames);
|
||||
dom.addClasses(this._domNode, findExpandedIcon.classNames);
|
||||
} else {
|
||||
dom.removeClasses(this._domNode, findExpandedIcon.classNames);
|
||||
dom.addClasses(this._domNode, findCollapsedIcon.classNames);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -276,7 +276,8 @@ suite('FindController', () => {
|
||||
seedSearchStringFromGlobalClipboard: false,
|
||||
shouldFocus: FindStartFocusAction.FocusFindInput,
|
||||
shouldAnimate: false,
|
||||
updateSearchScope: false
|
||||
updateSearchScope: false,
|
||||
loop: true
|
||||
});
|
||||
nextMatchFindAction.run(null, editor);
|
||||
startFindReplaceAction.run(null, editor);
|
||||
@@ -301,7 +302,8 @@ suite('FindController', () => {
|
||||
seedSearchStringFromGlobalClipboard: false,
|
||||
shouldFocus: FindStartFocusAction.NoFocusChange,
|
||||
shouldAnimate: false,
|
||||
updateSearchScope: false
|
||||
updateSearchScope: false,
|
||||
loop: true
|
||||
});
|
||||
|
||||
assert.equal(findController.getState().searchScope, null);
|
||||
@@ -530,7 +532,8 @@ suite('FindController query options persistence', () => {
|
||||
seedSearchStringFromGlobalClipboard: false,
|
||||
shouldFocus: FindStartFocusAction.NoFocusChange,
|
||||
shouldAnimate: false,
|
||||
updateSearchScope: true
|
||||
updateSearchScope: true,
|
||||
loop: true
|
||||
});
|
||||
|
||||
assert.deepEqual(findController.getState().searchScope, new Selection(1, 1, 2, 1));
|
||||
@@ -553,7 +556,8 @@ suite('FindController query options persistence', () => {
|
||||
seedSearchStringFromGlobalClipboard: false,
|
||||
shouldFocus: FindStartFocusAction.NoFocusChange,
|
||||
shouldAnimate: false,
|
||||
updateSearchScope: true
|
||||
updateSearchScope: true,
|
||||
loop: true
|
||||
});
|
||||
|
||||
assert.deepEqual(findController.getState().searchScope, null);
|
||||
@@ -576,7 +580,8 @@ suite('FindController query options persistence', () => {
|
||||
seedSearchStringFromGlobalClipboard: false,
|
||||
shouldFocus: FindStartFocusAction.NoFocusChange,
|
||||
shouldAnimate: false,
|
||||
updateSearchScope: true
|
||||
updateSearchScope: true,
|
||||
loop: true
|
||||
});
|
||||
|
||||
assert.deepEqual(findController.getState().searchScope, new Selection(1, 2, 1, 3));
|
||||
@@ -600,7 +605,8 @@ suite('FindController query options persistence', () => {
|
||||
seedSearchStringFromGlobalClipboard: false,
|
||||
shouldFocus: FindStartFocusAction.NoFocusChange,
|
||||
shouldAnimate: false,
|
||||
updateSearchScope: true
|
||||
updateSearchScope: true,
|
||||
loop: true
|
||||
});
|
||||
|
||||
assert.deepEqual(findController.getState().searchScope, new Selection(1, 6, 2, 1));
|
||||
|
||||
@@ -2089,4 +2089,165 @@ suite('FindModel', () => {
|
||||
findModel.dispose();
|
||||
findState.dispose();
|
||||
});
|
||||
|
||||
findTest('issue #3516: Control behavior of "Next" operations (not looping back to beginning)', (editor, cursor) => {
|
||||
let findState = new FindReplaceState();
|
||||
findState.change({ searchString: 'hello', loop: false }, false);
|
||||
let findModel = new FindModelBoundToEditorModel(editor, findState);
|
||||
|
||||
assert.equal(findState.matchesCount, 5);
|
||||
|
||||
// Test next operations
|
||||
assert.equal(findState.matchesPosition, 0);
|
||||
assert.equal(findState.canNavigateForward(), true);
|
||||
assert.equal(findState.canNavigateBack(), true);
|
||||
|
||||
findModel.moveToNextMatch();
|
||||
assert.equal(findState.matchesPosition, 1);
|
||||
assert.equal(findState.canNavigateForward(), true);
|
||||
assert.equal(findState.canNavigateBack(), false);
|
||||
|
||||
findModel.moveToNextMatch();
|
||||
assert.equal(findState.matchesPosition, 2);
|
||||
assert.equal(findState.canNavigateForward(), true);
|
||||
assert.equal(findState.canNavigateBack(), true);
|
||||
|
||||
findModel.moveToNextMatch();
|
||||
assert.equal(findState.matchesPosition, 3);
|
||||
assert.equal(findState.canNavigateForward(), true);
|
||||
assert.equal(findState.canNavigateBack(), true);
|
||||
|
||||
findModel.moveToNextMatch();
|
||||
assert.equal(findState.matchesPosition, 4);
|
||||
assert.equal(findState.canNavigateForward(), true);
|
||||
assert.equal(findState.canNavigateBack(), true);
|
||||
|
||||
findModel.moveToNextMatch();
|
||||
assert.equal(findState.matchesPosition, 5);
|
||||
assert.equal(findState.canNavigateForward(), false);
|
||||
assert.equal(findState.canNavigateBack(), true);
|
||||
|
||||
findModel.moveToNextMatch();
|
||||
assert.equal(findState.matchesPosition, 5);
|
||||
assert.equal(findState.canNavigateForward(), false);
|
||||
assert.equal(findState.canNavigateBack(), true);
|
||||
|
||||
findModel.moveToNextMatch();
|
||||
assert.equal(findState.matchesPosition, 5);
|
||||
assert.equal(findState.canNavigateForward(), false);
|
||||
assert.equal(findState.canNavigateBack(), true);
|
||||
|
||||
// Test previous operations
|
||||
findModel.moveToPrevMatch();
|
||||
assert.equal(findState.matchesPosition, 4);
|
||||
assert.equal(findState.canNavigateForward(), true);
|
||||
assert.equal(findState.canNavigateBack(), true);
|
||||
|
||||
findModel.moveToPrevMatch();
|
||||
assert.equal(findState.matchesPosition, 3);
|
||||
assert.equal(findState.canNavigateForward(), true);
|
||||
assert.equal(findState.canNavigateBack(), true);
|
||||
|
||||
findModel.moveToPrevMatch();
|
||||
assert.equal(findState.matchesPosition, 2);
|
||||
assert.equal(findState.canNavigateForward(), true);
|
||||
assert.equal(findState.canNavigateBack(), true);
|
||||
|
||||
findModel.moveToPrevMatch();
|
||||
assert.equal(findState.matchesPosition, 1);
|
||||
assert.equal(findState.canNavigateForward(), true);
|
||||
assert.equal(findState.canNavigateBack(), false);
|
||||
|
||||
findModel.moveToPrevMatch();
|
||||
assert.equal(findState.matchesPosition, 1);
|
||||
assert.equal(findState.canNavigateForward(), true);
|
||||
assert.equal(findState.canNavigateBack(), false);
|
||||
|
||||
findModel.moveToPrevMatch();
|
||||
assert.equal(findState.matchesPosition, 1);
|
||||
assert.equal(findState.canNavigateForward(), true);
|
||||
assert.equal(findState.canNavigateBack(), false);
|
||||
|
||||
});
|
||||
|
||||
findTest('issue #3516: Control behavior of "Next" operations (looping back to beginning)', (editor, cursor) => {
|
||||
let findState = new FindReplaceState();
|
||||
findState.change({ searchString: 'hello' }, false);
|
||||
let findModel = new FindModelBoundToEditorModel(editor, findState);
|
||||
|
||||
assert.equal(findState.matchesCount, 5);
|
||||
|
||||
// Test next operations
|
||||
assert.equal(findState.matchesPosition, 0);
|
||||
assert.equal(findState.canNavigateForward(), true);
|
||||
assert.equal(findState.canNavigateBack(), true);
|
||||
|
||||
findModel.moveToNextMatch();
|
||||
assert.equal(findState.matchesPosition, 1);
|
||||
assert.equal(findState.canNavigateForward(), true);
|
||||
assert.equal(findState.canNavigateBack(), true);
|
||||
|
||||
findModel.moveToNextMatch();
|
||||
assert.equal(findState.matchesPosition, 2);
|
||||
assert.equal(findState.canNavigateForward(), true);
|
||||
assert.equal(findState.canNavigateBack(), true);
|
||||
|
||||
findModel.moveToNextMatch();
|
||||
assert.equal(findState.matchesPosition, 3);
|
||||
assert.equal(findState.canNavigateForward(), true);
|
||||
assert.equal(findState.canNavigateBack(), true);
|
||||
|
||||
findModel.moveToNextMatch();
|
||||
assert.equal(findState.matchesPosition, 4);
|
||||
assert.equal(findState.canNavigateForward(), true);
|
||||
assert.equal(findState.canNavigateBack(), true);
|
||||
|
||||
findModel.moveToNextMatch();
|
||||
assert.equal(findState.matchesPosition, 5);
|
||||
assert.equal(findState.canNavigateForward(), true);
|
||||
assert.equal(findState.canNavigateBack(), true);
|
||||
|
||||
findModel.moveToNextMatch();
|
||||
assert.equal(findState.matchesPosition, 1);
|
||||
assert.equal(findState.canNavigateForward(), true);
|
||||
assert.equal(findState.canNavigateBack(), true);
|
||||
|
||||
findModel.moveToNextMatch();
|
||||
assert.equal(findState.matchesPosition, 2);
|
||||
assert.equal(findState.canNavigateForward(), true);
|
||||
assert.equal(findState.canNavigateBack(), true);
|
||||
|
||||
// Test previous operations
|
||||
findModel.moveToPrevMatch();
|
||||
assert.equal(findState.matchesPosition, 1);
|
||||
assert.equal(findState.canNavigateForward(), true);
|
||||
assert.equal(findState.canNavigateBack(), true);
|
||||
|
||||
findModel.moveToPrevMatch();
|
||||
assert.equal(findState.matchesPosition, 5);
|
||||
assert.equal(findState.canNavigateForward(), true);
|
||||
assert.equal(findState.canNavigateBack(), true);
|
||||
|
||||
findModel.moveToPrevMatch();
|
||||
assert.equal(findState.matchesPosition, 4);
|
||||
assert.equal(findState.canNavigateForward(), true);
|
||||
assert.equal(findState.canNavigateBack(), true);
|
||||
|
||||
findModel.moveToPrevMatch();
|
||||
assert.equal(findState.matchesPosition, 3);
|
||||
assert.equal(findState.canNavigateForward(), true);
|
||||
assert.equal(findState.canNavigateBack(), true);
|
||||
|
||||
findModel.moveToPrevMatch();
|
||||
assert.equal(findState.matchesPosition, 2);
|
||||
assert.equal(findState.canNavigateForward(), true);
|
||||
assert.equal(findState.canNavigateBack(), true);
|
||||
|
||||
findModel.moveToPrevMatch();
|
||||
assert.equal(findState.matchesPosition, 1);
|
||||
assert.equal(findState.canNavigateForward(), true);
|
||||
assert.equal(findState.canNavigateBack(), true);
|
||||
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
@@ -3,8 +3,8 @@
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
.monaco-editor .margin-view-overlays .codicon-chevron-right,
|
||||
.monaco-editor .margin-view-overlays .codicon-chevron-down {
|
||||
.monaco-editor .margin-view-overlays .codicon-folding-expanded,
|
||||
.monaco-editor .margin-view-overlays .codicon-folding-collapsed {
|
||||
cursor: pointer;
|
||||
opacity: 0;
|
||||
transition: opacity 0.5s;
|
||||
@@ -16,7 +16,7 @@
|
||||
}
|
||||
|
||||
.monaco-editor .margin-view-overlays:hover .codicon,
|
||||
.monaco-editor .margin-view-overlays .codicon.codicon-chevron-right,
|
||||
.monaco-editor .margin-view-overlays .codicon.codicon-folding-collapsed,
|
||||
.monaco-editor .margin-view-overlays .codicon.alwaysShowFoldIcons {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
@@ -33,7 +33,7 @@ import { KeybindingWeight } from 'vs/platform/keybinding/common/keybindingsRegis
|
||||
import { onUnexpectedError } from 'vs/base/common/errors';
|
||||
import { RawContextKey, IContextKey, IContextKeyService } from 'vs/platform/contextkey/common/contextkey';
|
||||
import { registerThemingParticipant } from 'vs/platform/theme/common/themeService';
|
||||
import { registerColor, editorSelectionBackground, transparent } from 'vs/platform/theme/common/colorRegistry';
|
||||
import { registerColor, editorSelectionBackground, transparent, iconForeground } from 'vs/platform/theme/common/colorRegistry';
|
||||
|
||||
const CONTEXT_FOLDING_ENABLED = new RawContextKey<boolean>('foldingEnabled', false);
|
||||
|
||||
@@ -898,10 +898,21 @@ for (let i = 1; i <= 7; i++) {
|
||||
}
|
||||
|
||||
export const foldBackgroundBackground = registerColor('editor.foldBackground', { light: transparent(editorSelectionBackground, 0.3), dark: transparent(editorSelectionBackground, 0.3), hc: null }, nls.localize('foldBackgroundBackground', "Background color behind folded ranges. The color must not be opaque so as not to hide underlying decorations."), true);
|
||||
export const editorFoldForeground = registerColor('editorGutter.foldingControlForeground', { dark: iconForeground, light: iconForeground, hc: iconForeground }, nls.localize('editorGutter.foldingControlForeground', 'Color of the folding control in the editor gutter.'));
|
||||
|
||||
registerThemingParticipant((theme, collector) => {
|
||||
const foldBackground = theme.getColor(foldBackgroundBackground);
|
||||
if (foldBackground) {
|
||||
collector.addRule(`.monaco-editor .folded-background { background-color: ${foldBackground}; }`);
|
||||
}
|
||||
|
||||
const editorFoldColor = theme.getColor(editorFoldForeground);
|
||||
if (editorFoldColor) {
|
||||
collector.addRule(`
|
||||
.monaco-editor .cldr.codicon-chevron-right,
|
||||
.monaco-editor .cldr.codicon-chevron-down {
|
||||
color: ${editorFoldColor} !important;
|
||||
}
|
||||
`);
|
||||
}
|
||||
});
|
||||
|
||||
@@ -7,6 +7,10 @@ import { TrackedRangeStickiness, IModelDeltaDecoration, IModelDecorationsChangeA
|
||||
import { ModelDecorationOptions } from 'vs/editor/common/model/textModel';
|
||||
import { IDecorationProvider } from 'vs/editor/contrib/folding/foldingModel';
|
||||
import { ICodeEditor } from 'vs/editor/browser/editorBrowser';
|
||||
import { Codicon, registerIcon } from 'vs/base/common/codicons';
|
||||
|
||||
const foldingExpandedIcon = registerIcon('folding-expanded', Codicon.chevronDown);
|
||||
const foldingCollapsedIcon = registerIcon('folding-collapsed', Codicon.chevronRight);
|
||||
|
||||
export class FoldingDecorationProvider implements IDecorationProvider {
|
||||
|
||||
@@ -14,7 +18,7 @@ export class FoldingDecorationProvider implements IDecorationProvider {
|
||||
stickiness: TrackedRangeStickiness.NeverGrowsWhenTypingAtEdges,
|
||||
afterContentClassName: 'inline-folded',
|
||||
isWholeLine: true,
|
||||
firstLineDecorationClassName: 'codicon codicon-chevron-right'
|
||||
firstLineDecorationClassName: foldingCollapsedIcon.classNames
|
||||
});
|
||||
|
||||
private static readonly COLLAPSED_HIGHLIGHTED_VISUAL_DECORATION = ModelDecorationOptions.register({
|
||||
@@ -22,19 +26,19 @@ export class FoldingDecorationProvider implements IDecorationProvider {
|
||||
afterContentClassName: 'inline-folded',
|
||||
className: 'folded-background',
|
||||
isWholeLine: true,
|
||||
firstLineDecorationClassName: 'codicon codicon-chevron-right'
|
||||
firstLineDecorationClassName: foldingCollapsedIcon.classNames
|
||||
});
|
||||
|
||||
private static readonly EXPANDED_AUTO_HIDE_VISUAL_DECORATION = ModelDecorationOptions.register({
|
||||
stickiness: TrackedRangeStickiness.NeverGrowsWhenTypingAtEdges,
|
||||
isWholeLine: true,
|
||||
firstLineDecorationClassName: 'codicon codicon-chevron-down'
|
||||
firstLineDecorationClassName: foldingExpandedIcon.classNames
|
||||
});
|
||||
|
||||
private static readonly EXPANDED_VISUAL_DECORATION = ModelDecorationOptions.register({
|
||||
stickiness: TrackedRangeStickiness.NeverGrowsWhenTypingAtEdges,
|
||||
isWholeLine: true,
|
||||
firstLineDecorationClassName: 'codicon codicon-chevron-down alwaysShowFoldIcons'
|
||||
firstLineDecorationClassName: 'alwaysShowFoldIcons ' + foldingExpandedIcon.classNames
|
||||
});
|
||||
|
||||
private static readonly HIDDEN_RANGE_DECORATION = ModelDecorationOptions.register({
|
||||
|
||||
@@ -151,6 +151,26 @@ export class FoldingRegions {
|
||||
}
|
||||
return res.join(', ');
|
||||
}
|
||||
|
||||
public equals(b: FoldingRegions) {
|
||||
if (this.length !== b.length) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for (let i = 0; i < this.length; i++) {
|
||||
if (this.getStartLineNumber(i) !== b.getStartLineNumber(i)) {
|
||||
return false;
|
||||
}
|
||||
if (this.getEndLineNumber(i) !== b.getEndLineNumber(i)) {
|
||||
return false;
|
||||
}
|
||||
if (this.getType(i) !== b.getType(i)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
export class FoldingRegion {
|
||||
|
||||
@@ -29,6 +29,7 @@ import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding';
|
||||
import { isEqual } from 'vs/base/common/resources';
|
||||
import { IOpenerService } from 'vs/platform/opener/common/opener';
|
||||
import { TextEditorSelectionRevealType } from 'vs/platform/editor/common/editor';
|
||||
import { Codicon, registerIcon } from 'vs/base/common/codicons';
|
||||
|
||||
class MarkerModel {
|
||||
|
||||
@@ -191,6 +192,9 @@ class MarkerModel {
|
||||
}
|
||||
}
|
||||
|
||||
const markerNavigationNextIcon = registerIcon('marker-navigation-next', Codicon.chevronDown);
|
||||
const markerNavigationPreviousIcon = registerIcon('marker-navigation-previous', Codicon.chevronUp);
|
||||
|
||||
export class MarkerController implements IEditorContribution {
|
||||
|
||||
public static readonly ID = 'editor.contrib.markerController';
|
||||
@@ -243,8 +247,8 @@ export class MarkerController implements IEditorContribution {
|
||||
const prevMarkerKeybinding = this._keybindingService.lookupKeybinding(PrevMarkerAction.ID);
|
||||
const nextMarkerKeybinding = this._keybindingService.lookupKeybinding(NextMarkerAction.ID);
|
||||
const actions = [
|
||||
new Action(NextMarkerAction.ID, NextMarkerAction.LABEL + (nextMarkerKeybinding ? ` (${nextMarkerKeybinding.getLabel()})` : ''), 'show-next-problem codicon-chevron-down', this._model.canNavigate(), async () => { if (this._model) { this._model.move(true, true); } }),
|
||||
new Action(PrevMarkerAction.ID, PrevMarkerAction.LABEL + (prevMarkerKeybinding ? ` (${prevMarkerKeybinding.getLabel()})` : ''), 'show-previous-problem codicon-chevron-up', this._model.canNavigate(), async () => { if (this._model) { this._model.move(false, true); } })
|
||||
new Action(NextMarkerAction.ID, NextMarkerAction.LABEL + (nextMarkerKeybinding ? ` (${nextMarkerKeybinding.getLabel()})` : ''), 'show-next-problem ' + markerNavigationNextIcon.classNames, this._model.canNavigate(), async () => { if (this._model) { this._model.move(true, true); } }),
|
||||
new Action(PrevMarkerAction.ID, PrevMarkerAction.LABEL + (prevMarkerKeybinding ? ` (${prevMarkerKeybinding.getLabel()})` : ''), 'show-previous-problem ' + markerNavigationPreviousIcon.classNames, this._model.canNavigate(), async () => { if (this._model) { this._model.move(false, true); } })
|
||||
];
|
||||
this._widget = new MarkerNavigationWidget(this._editor, actions, this._themeService, this._openerService);
|
||||
this._widgetVisible.set(true);
|
||||
|
||||
@@ -11,19 +11,19 @@ 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 { values } from 'vs/base/common/collections';
|
||||
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 values(model.children)) {
|
||||
for (const child of model.children.values()) {
|
||||
if (child instanceof OutlineElement) {
|
||||
roots.push(child.symbol);
|
||||
} else {
|
||||
roots.push(...values(child.children).map(child => child.symbol));
|
||||
roots.push(...Iterable.map(child.children.values(), child => child.symbol));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -17,7 +17,7 @@ import { getBaseLabel } from 'vs/base/common/labels';
|
||||
import { dirname, basename } from 'vs/base/common/resources';
|
||||
import { Disposable } from 'vs/base/common/lifecycle';
|
||||
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
|
||||
import { IAccessibilityProvider } from 'vs/base/browser/ui/list/listWidget';
|
||||
import { IListAccessibilityProvider } from 'vs/base/browser/ui/list/listWidget';
|
||||
import { IListVirtualDelegate, IKeyboardNavigationLabelProvider, IIdentityProvider } from 'vs/base/browser/ui/list/list';
|
||||
import { IKeyboardEvent } from 'vs/base/browser/keyboardEvent';
|
||||
import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding';
|
||||
@@ -213,7 +213,11 @@ export class OneReferenceRenderer implements ITreeRenderer<OneReference, FuzzySc
|
||||
//#endregion
|
||||
|
||||
|
||||
export class AriaProvider implements IAccessibilityProvider<FileReferences | OneReference> {
|
||||
export class AccessibilityProvider implements IListAccessibilityProvider<FileReferences | OneReference> {
|
||||
|
||||
getWidgetAriaLabel(): string {
|
||||
return localize('treeAriaLabel', "References");
|
||||
}
|
||||
|
||||
getAriaLabel(element: FileReferences | OneReference): string | null {
|
||||
return element.ariaMessage;
|
||||
|
||||
@@ -22,7 +22,7 @@ import { IModelDeltaDecoration, TrackedRangeStickiness } from 'vs/editor/common/
|
||||
import { ModelDecorationOptions, TextModel } from 'vs/editor/common/model/textModel';
|
||||
import { Location } from 'vs/editor/common/modes';
|
||||
import { ITextEditorModel, ITextModelService } from 'vs/editor/common/services/resolverService';
|
||||
import { AriaProvider, DataSource, Delegate, FileReferencesRenderer, OneReferenceRenderer, TreeElement, StringRepresentationProvider, IdentityProvider } from 'vs/editor/contrib/gotoSymbol/peek/referencesTree';
|
||||
import { AccessibilityProvider, DataSource, Delegate, FileReferencesRenderer, OneReferenceRenderer, TreeElement, StringRepresentationProvider, IdentityProvider } from 'vs/editor/contrib/gotoSymbol/peek/referencesTree';
|
||||
import * as nls from 'vs/nls';
|
||||
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
|
||||
import { ILabelService } from 'vs/platform/label/common/label';
|
||||
@@ -311,9 +311,8 @@ export class ReferenceWidget extends peekView.PeekViewWidget {
|
||||
// tree
|
||||
this._treeContainer = dom.append(containerElement, dom.$('div.ref-tree.inline'));
|
||||
const treeOptions: IWorkbenchAsyncDataTreeOptions<TreeElement, FuzzyScore> = {
|
||||
ariaLabel: nls.localize('treeAriaLabel', "References"),
|
||||
keyboardSupport: this._defaultTreeKeyboardSupport,
|
||||
accessibilityProvider: new AriaProvider(),
|
||||
accessibilityProvider: new AccessibilityProvider(),
|
||||
keyboardNavigationLabelProvider: this._instantiationService.createInstance(StringRepresentationProvider),
|
||||
identityProvider: new IdentityProvider(),
|
||||
overrideStyles: {
|
||||
|
||||
@@ -30,7 +30,7 @@
|
||||
}
|
||||
|
||||
.monaco-editor-hover .markdown-hover > .hover-contents:not(.code-hover-contents) hr {
|
||||
min-width: 100vw;
|
||||
min-width: 100%;
|
||||
}
|
||||
|
||||
.monaco-editor-hover p,
|
||||
|
||||
@@ -143,9 +143,7 @@ export class HoverOperation<Result> {
|
||||
}
|
||||
|
||||
private _onComplete(value: Result): void {
|
||||
if (this._completeCallback) {
|
||||
this._completeCallback(value);
|
||||
}
|
||||
this._completeCallback(value);
|
||||
}
|
||||
|
||||
private _onError(error: any): void {
|
||||
@@ -157,9 +155,7 @@ export class HoverOperation<Result> {
|
||||
}
|
||||
|
||||
private _onProgress(value: Result): void {
|
||||
if (this._progressCallback) {
|
||||
this._progressCallback(value);
|
||||
}
|
||||
this._progressCallback(value);
|
||||
}
|
||||
|
||||
public start(mode: HoverStartMode): void {
|
||||
|
||||
@@ -47,6 +47,7 @@ export class ContentHoverWidget extends Widget implements IContentWidget {
|
||||
this._containerDomNode = document.createElement('div');
|
||||
this._containerDomNode.className = 'monaco-editor-hover hidden';
|
||||
this._containerDomNode.tabIndex = 0;
|
||||
this._containerDomNode.setAttribute('role', 'tooltip');
|
||||
|
||||
this._domNode = document.createElement('div');
|
||||
this._domNode.className = 'monaco-editor-hover-content';
|
||||
@@ -178,7 +179,7 @@ export class GlyphHoverWidget extends Widget implements IOverlayWidget {
|
||||
this._domNode = document.createElement('div');
|
||||
this._domNode.className = 'monaco-editor-hover hidden';
|
||||
this._domNode.setAttribute('aria-hidden', 'true');
|
||||
this._domNode.setAttribute('role', 'presentation');
|
||||
this._domNode.setAttribute('role', 'tooltip');
|
||||
|
||||
this._showAtLineNumber = -1;
|
||||
|
||||
|
||||
@@ -607,6 +607,9 @@ export class ModesContentHoverWidget extends ContentHoverWidget {
|
||||
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
|
||||
@@ -633,6 +636,8 @@ export class ModesContentHoverWidget extends ContentHoverWidget {
|
||||
private renderAction(parent: HTMLElement, actionOptions: { label: string, iconClass?: string, run: (target: HTMLElement) => void, commandId: string }): IDisposable {
|
||||
const actionContainer = dom.append(parent, $('div.action-container'));
|
||||
const action = dom.append(actionContainer, $('a.action'));
|
||||
action.setAttribute('href', '#');
|
||||
action.setAttribute('role', 'button');
|
||||
if (actionOptions.iconClass) {
|
||||
dom.append(action, $(`span.icon.${actionOptions.iconClass}`));
|
||||
}
|
||||
|
||||
@@ -23,9 +23,13 @@ import { editorHoverBackground, editorHoverBorder, textCodeBlockBackground, text
|
||||
import { HIGH_CONTRAST, registerThemingParticipant } from 'vs/platform/theme/common/themeService';
|
||||
import { ParameterHintsModel, TriggerContext } from 'vs/editor/contrib/parameterHints/parameterHintsModel';
|
||||
import { pad } from 'vs/base/common/strings';
|
||||
import { registerIcon, Codicon } from 'vs/base/common/codicons';
|
||||
|
||||
const $ = dom.$;
|
||||
|
||||
const parameterHintsNextIcon = registerIcon('parameter-hints-next', Codicon.chevronDown);
|
||||
const parameterHintsPreviousIcon = registerIcon('parameter-hints-previous', Codicon.chevronUp);
|
||||
|
||||
export class ParameterHintsWidget extends Disposable implements IContentWidget {
|
||||
|
||||
private static readonly ID = 'editor.widget.parameterHintsWidget';
|
||||
@@ -78,9 +82,9 @@ export class ParameterHintsWidget extends Disposable implements IContentWidget {
|
||||
wrapper.tabIndex = -1;
|
||||
|
||||
const controls = dom.append(wrapper, $('.controls'));
|
||||
const previous = dom.append(controls, $('.button.codicon.codicon-chevron-up'));
|
||||
const previous = dom.append(controls, $('.button' + parameterHintsPreviousIcon.cssSelector));
|
||||
const overloads = dom.append(controls, $('.overloads'));
|
||||
const next = dom.append(controls, $('.button.codicon.codicon-chevron-down'));
|
||||
const next = dom.append(controls, $('.button' + parameterHintsNextIcon.cssSelector));
|
||||
|
||||
const onPreviousClick = stop(domEvent(previous, 'click'));
|
||||
this._register(onPreviousClick(this.previous, this));
|
||||
@@ -153,6 +157,8 @@ export class ParameterHintsWidget extends Disposable implements IContentWidget {
|
||||
}
|
||||
|
||||
private hide(): void {
|
||||
this.renderDisposeables.clear();
|
||||
|
||||
if (!this.visible) {
|
||||
return;
|
||||
}
|
||||
@@ -177,6 +183,8 @@ export class ParameterHintsWidget extends Disposable implements IContentWidget {
|
||||
}
|
||||
|
||||
private render(hints: modes.SignatureHelp): void {
|
||||
this.renderDisposeables.clear();
|
||||
|
||||
if (!this.domNodes) {
|
||||
return;
|
||||
}
|
||||
@@ -194,43 +202,40 @@ export class ParameterHintsWidget extends Disposable implements IContentWidget {
|
||||
}
|
||||
|
||||
const code = dom.append(this.domNodes.signature, $('.code'));
|
||||
const hasParameters = signature.parameters.length > 0;
|
||||
|
||||
const fontInfo = this.editor.getOption(EditorOption.fontInfo);
|
||||
code.style.fontSize = `${fontInfo.fontSize}px`;
|
||||
code.style.fontFamily = fontInfo.fontFamily;
|
||||
|
||||
const hasParameters = signature.parameters.length > 0;
|
||||
const activeParameterIndex = signature.activeParameter ?? hints.activeParameter;
|
||||
|
||||
if (!hasParameters) {
|
||||
const label = dom.append(code, $('span'));
|
||||
label.textContent = signature.label;
|
||||
} else {
|
||||
this.renderParameters(code, signature, hints.activeParameter);
|
||||
this.renderParameters(code, signature, activeParameterIndex);
|
||||
}
|
||||
|
||||
this.renderDisposeables.clear();
|
||||
|
||||
const activeParameter: modes.ParameterInformation | undefined = signature.parameters[hints.activeParameter];
|
||||
|
||||
if (activeParameter && activeParameter.documentation) {
|
||||
const activeParameter: modes.ParameterInformation | undefined = signature.parameters[activeParameterIndex];
|
||||
if (activeParameter?.documentation) {
|
||||
const documentation = $('span.documentation');
|
||||
if (typeof activeParameter.documentation === 'string') {
|
||||
documentation.textContent = activeParameter.documentation;
|
||||
} else {
|
||||
const renderedContents = this.markdownRenderer.render(activeParameter.documentation);
|
||||
const renderedContents = this.renderDisposeables.add(this.markdownRenderer.render(activeParameter.documentation));
|
||||
dom.addClass(renderedContents.element, 'markdown-docs');
|
||||
this.renderDisposeables.add(renderedContents);
|
||||
documentation.appendChild(renderedContents.element);
|
||||
}
|
||||
dom.append(this.domNodes.docs, $('p', {}, documentation));
|
||||
}
|
||||
|
||||
if (signature.documentation === undefined) { /** no op */ }
|
||||
else if (typeof signature.documentation === 'string') {
|
||||
if (signature.documentation === undefined) {
|
||||
/** no op */
|
||||
} else if (typeof signature.documentation === 'string') {
|
||||
dom.append(this.domNodes.docs, $('p', {}, signature.documentation));
|
||||
} else {
|
||||
const renderedContents = this.markdownRenderer.render(signature.documentation);
|
||||
const renderedContents = this.renderDisposeables.add(this.markdownRenderer.render(signature.documentation));
|
||||
dom.addClass(renderedContents.element, 'markdown-docs');
|
||||
this.renderDisposeables.add(renderedContents);
|
||||
dom.append(this.domNodes.docs, renderedContents.element);
|
||||
}
|
||||
|
||||
@@ -243,7 +248,7 @@ export class ParameterHintsWidget extends Disposable implements IContentWidget {
|
||||
pad(hints.activeSignature + 1, hints.signatures.length.toString().length) + '/' + hints.signatures.length;
|
||||
|
||||
if (activeParameter) {
|
||||
const labelToAnnounce = this.getParameterLabel(signature, hints.activeParameter);
|
||||
const labelToAnnounce = this.getParameterLabel(signature, activeParameterIndex);
|
||||
// Select method gets called on every user type while parameter hints are visible.
|
||||
// We do not want to spam the user with same announcements, so we only announce if the current parameter changed.
|
||||
|
||||
@@ -273,8 +278,8 @@ export class ParameterHintsWidget extends Disposable implements IContentWidget {
|
||||
return false;
|
||||
}
|
||||
|
||||
private renderParameters(parent: HTMLElement, signature: modes.SignatureInformation, currentParameter: number): void {
|
||||
const [start, end] = this.getParameterLabelOffsets(signature, currentParameter);
|
||||
private renderParameters(parent: HTMLElement, signature: modes.SignatureInformation, activeParameterIndex: number): void {
|
||||
const [start, end] = this.getParameterLabelOffsets(signature, activeParameterIndex);
|
||||
|
||||
const beforeSpan = document.createElement('span');
|
||||
beforeSpan.textContent = signature.label.substring(0, start);
|
||||
|
||||
@@ -25,6 +25,7 @@ import { EditorOption } from 'vs/editor/common/config/editorOptions';
|
||||
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';
|
||||
|
||||
|
||||
export const IPeekViewService = createDecorator<IPeekViewService>('IPeekViewService');
|
||||
@@ -186,7 +187,7 @@ export abstract class PeekViewWidget extends ZoneWidget {
|
||||
this._actionbarWidget = new ActionBar(actionsContainer, actionBarOptions);
|
||||
this._disposables.add(this._actionbarWidget);
|
||||
|
||||
this._actionbarWidget.push(new Action('peekview.close', nls.localize('label.close', "Close"), 'codicon-close', true, () => {
|
||||
this._actionbarWidget.push(new Action('peekview.close', nls.localize('label.close', "Close"), Codicon.close.classNames, true, () => {
|
||||
this.dispose();
|
||||
return Promise.resolve();
|
||||
}), { label: false, icon: true });
|
||||
|
||||
@@ -13,10 +13,11 @@ import { IRange, Range } from 'vs/editor/common/core/range';
|
||||
import { AbstractEditorNavigationQuickAccessProvider, IEditorNavigationQuickAccessOptions } 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 { values } from 'vs/base/common/collections';
|
||||
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 {
|
||||
kind: SymbolKind,
|
||||
@@ -35,15 +36,14 @@ export abstract class AbstractGotoSymbolQuickAccessProvider extends AbstractEdit
|
||||
static SCOPE_PREFIX = ':';
|
||||
static PREFIX_BY_CATEGORY = `${AbstractGotoSymbolQuickAccessProvider.PREFIX}${AbstractGotoSymbolQuickAccessProvider.SCOPE_PREFIX}`;
|
||||
|
||||
constructor(protected options?: IGotoSymbolQuickAccessProviderOptions) {
|
||||
super({ ...options, canAcceptInBackground: true });
|
||||
constructor(protected options: IGotoSymbolQuickAccessProviderOptions = Object.create(null)) {
|
||||
super(options);
|
||||
|
||||
options.canAcceptInBackground = true;
|
||||
}
|
||||
|
||||
protected provideWithoutTextEditor(picker: IQuickPick<IGotoSymbolQuickPickItem>): IDisposable {
|
||||
const label = localize('cannotRunGotoSymbolWithoutEditor', "To go to a symbol, first open a text editor with symbol information.");
|
||||
|
||||
picker.items = [{ label, index: 0, kind: SymbolKind.String }];
|
||||
picker.ariaLabel = label;
|
||||
this.provideLabelPick(picker, localize('cannotRunGotoSymbolWithoutEditor', "To go to a symbol, first open a text editor with symbol information."));
|
||||
|
||||
return Disposable.None;
|
||||
}
|
||||
@@ -69,9 +69,7 @@ export abstract class AbstractGotoSymbolQuickAccessProvider extends AbstractEdit
|
||||
const disposables = new DisposableStore();
|
||||
|
||||
// Generic pick for not having any symbol information
|
||||
const label = localize('cannotRunGotoSymbolWithoutSymbolProvider', "The active text editor does not provide symbol information.");
|
||||
picker.items = [{ label, index: 0, kind: SymbolKind.String }];
|
||||
picker.ariaLabel = label;
|
||||
this.provideLabelPick(picker, localize('cannotRunGotoSymbolWithoutSymbolProvider', "The active text editor does not provide symbol information."));
|
||||
|
||||
// Wait for changes to the registry and see if eventually
|
||||
// we do get symbols. This can happen if the picker is opened
|
||||
@@ -90,6 +88,11 @@ export abstract class AbstractGotoSymbolQuickAccessProvider extends AbstractEdit
|
||||
return disposables;
|
||||
}
|
||||
|
||||
private provideLabelPick(picker: IQuickPick<IGotoSymbolQuickPickItem>, label: string): void {
|
||||
picker.items = [{ label, index: 0, kind: SymbolKind.String }];
|
||||
picker.ariaLabel = label;
|
||||
}
|
||||
|
||||
protected async waitForLanguageSymbolRegistry(model: ITextModel, disposables: DisposableStore): Promise<boolean> {
|
||||
if (DocumentSymbolProviderRegistry.has(model)) {
|
||||
return true;
|
||||
@@ -155,12 +158,21 @@ export abstract class AbstractGotoSymbolQuickAccessProvider extends AbstractEdit
|
||||
// Collect symbol picks
|
||||
picker.busy = true;
|
||||
try {
|
||||
const items = await this.doGetSymbolPicks(symbolsPromise, prepareQuery(picker.value.substr(AbstractGotoSymbolQuickAccessProvider.PREFIX.length).trim()), undefined, picksCts.token);
|
||||
const query = prepareQuery(picker.value.substr(AbstractGotoSymbolQuickAccessProvider.PREFIX.length).trim());
|
||||
const items = await this.doGetSymbolPicks(symbolsPromise, query, undefined, picksCts.token);
|
||||
if (token.isCancellationRequested) {
|
||||
return;
|
||||
}
|
||||
|
||||
picker.items = items;
|
||||
if (items.length > 0) {
|
||||
picker.items = items;
|
||||
} else {
|
||||
if (query.original.length > 0) {
|
||||
this.provideLabelPick(picker, localize('noMatchingSymbolResults', "No matching editor symbols"));
|
||||
} else {
|
||||
this.provideLabelPick(picker, localize('noSymbolResults', "No editor symbols"));
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
if (!token.isCancellationRequested) {
|
||||
picker.busy = false;
|
||||
@@ -220,6 +232,7 @@ export abstract class AbstractGotoSymbolQuickAccessProvider extends AbstractEdit
|
||||
|
||||
const symbolLabel = trim(symbol.name);
|
||||
const symbolLabelWithIcon = `$(symbol-${SymbolKinds.toString(symbol.kind) || 'property'}) ${symbolLabel}`;
|
||||
const symbolLabelIconOffset = symbolLabelWithIcon.length - symbolLabel.length;
|
||||
|
||||
let containerLabel = symbol.containerName;
|
||||
if (options?.extraContainerLabel) {
|
||||
@@ -238,23 +251,37 @@ export abstract class AbstractGotoSymbolQuickAccessProvider extends AbstractEdit
|
||||
|
||||
if (query.original.length > filterPos) {
|
||||
|
||||
// Score by symbol
|
||||
[symbolScore, symbolMatches] = scoreFuzzy2(symbolLabel, symbolQuery, filterPos, symbolLabelWithIcon.length - symbolLabel.length /* Readjust matches to account for codicons in label */);
|
||||
if (!symbolScore) {
|
||||
continue;
|
||||
// First: try to score on the entire query, it is possible that
|
||||
// the symbol matches perfectly (e.g. searching for "change log"
|
||||
// can be a match on a markdown symbol "change log"). In that
|
||||
// case we want to skip the container query altogether.
|
||||
let skipContainerQuery = false;
|
||||
if (symbolQuery !== query) {
|
||||
[symbolScore, symbolMatches] = scoreFuzzy2(symbolLabel, { ...query, values: undefined /* disable multi-query support */ }, filterPos, symbolLabelIconOffset);
|
||||
if (typeof symbolScore === 'number') {
|
||||
skipContainerQuery = true; // since we consumed the query, skip any container matching
|
||||
}
|
||||
}
|
||||
|
||||
// Otherwise: score on the symbol query and match on the container later
|
||||
if (typeof symbolScore !== 'number') {
|
||||
[symbolScore, symbolMatches] = scoreFuzzy2(symbolLabel, symbolQuery, filterPos, symbolLabelIconOffset);
|
||||
if (typeof symbolScore !== 'number') {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
// Score by container if specified
|
||||
if (containerQuery) {
|
||||
if (!skipContainerQuery && containerQuery) {
|
||||
if (containerLabel && containerQuery.original.length > 0) {
|
||||
[containerScore, containerMatches] = scoreFuzzy2(containerLabel, containerQuery);
|
||||
}
|
||||
|
||||
if (!containerScore) {
|
||||
if (typeof containerScore !== 'number') {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (symbolScore) {
|
||||
if (typeof symbolScore === 'number') {
|
||||
symbolScore += containerScore; // boost symbolScore by containerScore
|
||||
}
|
||||
}
|
||||
@@ -286,7 +313,7 @@ export abstract class AbstractGotoSymbolQuickAccessProvider extends AbstractEdit
|
||||
|
||||
return [
|
||||
{
|
||||
iconClass: openSideBySideDirection === 'right' ? 'codicon-split-horizontal' : 'codicon-split-vertical',
|
||||
iconClass: openSideBySideDirection === 'right' ? Codicon.splitHorizontal.classNames : Codicon.splitVertical.classNames,
|
||||
tooltip: openSideBySideDirection === 'right' ? localize('openToSide', "Open to the Side") : localize('openToBottom', "Open to the Bottom")
|
||||
}
|
||||
];
|
||||
@@ -342,7 +369,7 @@ export abstract class AbstractGotoSymbolQuickAccessProvider extends AbstractEdit
|
||||
|
||||
// Update last separator with number of symbols we found for kind
|
||||
updateLastSeparatorLabel();
|
||||
} else {
|
||||
} else if (sortedFilteredSymbolPicks.length > 0) {
|
||||
symbolPicks = [
|
||||
{ label: localize('symbols', "symbols ({0})", filteredSymbolPicks.length), type: 'separator' },
|
||||
...sortedFilteredSymbolPicks
|
||||
@@ -353,13 +380,13 @@ export abstract class AbstractGotoSymbolQuickAccessProvider extends AbstractEdit
|
||||
}
|
||||
|
||||
private compareByScore(symbolA: IGotoSymbolQuickPickItem, symbolB: IGotoSymbolQuickPickItem): number {
|
||||
if (!symbolA.score && symbolB.score) {
|
||||
if (typeof symbolA.score !== 'number' && typeof symbolB.score === 'number') {
|
||||
return 1;
|
||||
} else if (symbolA.score && !symbolB.score) {
|
||||
} else if (typeof symbolA.score === 'number' && typeof symbolB.score !== 'number') {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (symbolA.score && symbolB.score) {
|
||||
if (typeof symbolA.score === 'number' && typeof symbolB.score === 'number') {
|
||||
if (symbolA.score > symbolB.score) {
|
||||
return -1;
|
||||
} else if (symbolA.score < symbolB.score) {
|
||||
@@ -396,11 +423,11 @@ export abstract class AbstractGotoSymbolQuickAccessProvider extends AbstractEdit
|
||||
}
|
||||
|
||||
const roots: DocumentSymbol[] = [];
|
||||
for (const child of values(model.children)) {
|
||||
for (const child of model.children.values()) {
|
||||
if (child instanceof OutlineElement) {
|
||||
roots.push(child.symbol);
|
||||
} else {
|
||||
roots.push(...values(child.children).map(child => child.symbol));
|
||||
roots.push(...Iterable.map(child.children.values(), child => child.symbol));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
|
||||
import 'vs/css!./media/suggest';
|
||||
import 'vs/css!./media/suggestStatusBar';
|
||||
import 'vs/base/browser/ui/codiconLabel/codiconLabel'; // The codicon symbol styles are defined here and must be loaded
|
||||
import 'vs/base/browser/ui/codicons/codiconStyles'; // The codicon symbol styles are defined here and must be loaded
|
||||
import 'vs/editor/contrib/documentSymbols/outlineTree'; // The codicon symbol colors are defined here and must be loaded
|
||||
import * as nls from 'vs/nls';
|
||||
import { createMatches } from 'vs/base/common/filters';
|
||||
@@ -45,9 +45,12 @@ import { IKeyboardEvent } from 'vs/base/browser/keyboardEvent';
|
||||
import { IMenuService } from 'vs/platform/actions/common/actions';
|
||||
import { ActionBar, IActionViewItemProvider, ActionViewItem } from 'vs/base/browser/ui/actionbar/actionbar';
|
||||
import { IAction } from 'vs/base/common/actions';
|
||||
import { Codicon, registerIcon } from 'vs/base/common/codicons';
|
||||
|
||||
const expandSuggestionDocsByDefault = false;
|
||||
|
||||
const suggestMoreInfoIcon = registerIcon('suggest-more-info', Codicon.chevronRight);
|
||||
|
||||
interface ISuggestionTemplateData {
|
||||
root: HTMLElement;
|
||||
|
||||
@@ -155,7 +158,7 @@ class ItemRenderer implements IListRenderer<CompletionItem, ISuggestionTemplateD
|
||||
data.qualifierLabel = append(data.left, $('span.qualifier-label'));
|
||||
data.detailsLabel = append(data.right, $('span.details-label'));
|
||||
|
||||
data.readMore = append(data.right, $('span.readMore.codicon.codicon-info'));
|
||||
data.readMore = append(data.right, $('span.readMore' + suggestMoreInfoIcon.cssSelector));
|
||||
data.readMore.title = nls.localize('readMore', "Read More...{0}", this.triggerKeybindingLabel);
|
||||
|
||||
const configureFont = () => {
|
||||
@@ -229,7 +232,7 @@ class ItemRenderer implements IListRenderer<CompletionItem, ISuggestionTemplateD
|
||||
// normal icon
|
||||
data.icon.className = 'icon hide';
|
||||
data.iconContainer.className = '';
|
||||
addClasses(data.iconContainer, `suggest-icon codicon codicon-${completionKindToCssClass(suggestion.kind)}`);
|
||||
addClasses(data.iconContainer, `suggest-icon ${completionKindToCssClass(suggestion.kind)}`);
|
||||
}
|
||||
|
||||
if (suggestion.tags && suggestion.tags.indexOf(CompletionItemTag.Deprecated) >= 0) {
|
||||
@@ -317,7 +320,7 @@ class SuggestionDetails {
|
||||
this.disposables.add(this.scrollbar);
|
||||
|
||||
this.header = append(this.body, $('.header'));
|
||||
this.close = append(this.header, $('span.codicon.codicon-close'));
|
||||
this.close = append(this.header, $('span' + Codicon.close.cssSelector));
|
||||
this.close.title = nls.localize('readLess', "Read less...{0}", this.kbToggleDetails);
|
||||
this.type = append(this.header, $('p.type'));
|
||||
|
||||
@@ -604,13 +607,8 @@ export class SuggestWidget implements IContentWidget, IListVirtualDelegate<Compl
|
||||
useShadows: false,
|
||||
openController: { shouldOpen: () => false },
|
||||
mouseSupport: false,
|
||||
ariaRole: 'listbox',
|
||||
ariaProvider: {
|
||||
getRole: () => 'option',
|
||||
getSetSize: (_: CompletionItem, _index: number, listLength: number) => listLength,
|
||||
getPosInSet: (_: CompletionItem, index: number) => index,
|
||||
},
|
||||
accessibilityProvider: {
|
||||
getRole: () => 'option',
|
||||
getAriaLabel: (item: CompletionItem) => {
|
||||
const textLabel = typeof item.completion.label === 'string' ? item.completion.label : item.completion.label.name;
|
||||
if (item.isResolved && this.expandDocsSettingFromStorage()) {
|
||||
@@ -624,7 +622,9 @@ export class SuggestWidget implements IContentWidget, IListVirtualDelegate<Compl
|
||||
} else {
|
||||
return textLabel;
|
||||
}
|
||||
}
|
||||
},
|
||||
getWidgetAriaLabel: () => nls.localize('suggest', "Suggest"),
|
||||
getWidgetRole: () => 'listbox'
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
@@ -48,3 +48,5 @@ import 'vs/editor/contrib/wordPartOperations/wordPartOperations';
|
||||
// Load up these strings even in VSCode, even if they are not used
|
||||
// in order to get them translated
|
||||
import 'vs/editor/common/standaloneStrings';
|
||||
|
||||
import 'vs/base/browser/ui/codicons/codiconStyles'; // The codicons are defined here and must be loaded
|
||||
|
||||
@@ -90,11 +90,11 @@ export class StandaloneQuickInputServiceImpl implements IQuickInputService {
|
||||
) {
|
||||
}
|
||||
|
||||
pick<T extends IQuickPickItem, O extends IPickOptions<T>>(picks: Promise<QuickPickInput<T>[]> | QuickPickInput<T>[], options: O = <O>{}, token: CancellationToken = CancellationToken.None): Promise<O extends { canPickMany: true } ? T[] : T> {
|
||||
pick<T extends IQuickPickItem, O extends IPickOptions<T>>(picks: Promise<QuickPickInput<T>[]> | QuickPickInput<T>[], options: O = <O>{}, token: CancellationToken = CancellationToken.None): Promise<(O extends { canPickMany: true } ? T[] : T) | undefined> {
|
||||
return (this.activeService as unknown as QuickInputController /* TS fail */).pick(picks, options, token);
|
||||
}
|
||||
|
||||
input(options?: IInputOptions | undefined, token?: CancellationToken | undefined): Promise<string> {
|
||||
input(options?: IInputOptions | undefined, token?: CancellationToken | undefined): Promise<string | undefined> {
|
||||
return this.activeService.input(options, token);
|
||||
}
|
||||
|
||||
|
||||
@@ -40,6 +40,7 @@ import { IAccessibilityService } from 'vs/platform/accessibility/common/accessib
|
||||
import { clearAllFontInfos } from 'vs/editor/browser/config/configuration';
|
||||
import { IEditorProgressService } from 'vs/platform/progress/common/progress';
|
||||
import { IClipboardService } from 'vs/platform/clipboard/common/clipboardService';
|
||||
import { StandaloneThemeServiceImpl } from 'vs/editor/standalone/browser/standaloneThemeServiceImpl';
|
||||
|
||||
type Omit<T, K extends keyof T> = Pick<T, Exclude<keyof T, K>>;
|
||||
|
||||
@@ -241,13 +242,17 @@ export function createWebWorker<T>(opts: IWebWorkerOptions): MonacoWebWorker<T>
|
||||
* Colorize the contents of `domNode` using attribute `data-lang`.
|
||||
*/
|
||||
export function colorizeElement(domNode: HTMLElement, options: IColorizerElementOptions): Promise<void> {
|
||||
return Colorizer.colorizeElement(StaticServices.standaloneThemeService.get(), StaticServices.modeService.get(), domNode, options);
|
||||
const themeService = <StandaloneThemeServiceImpl>StaticServices.standaloneThemeService.get();
|
||||
themeService.registerEditorContainer(domNode);
|
||||
return Colorizer.colorizeElement(themeService, StaticServices.modeService.get(), domNode, options);
|
||||
}
|
||||
|
||||
/**
|
||||
* Colorize `text` using language `languageId`.
|
||||
*/
|
||||
export function colorize(text: string, languageId: string, options: IColorizerOptions): Promise<string> {
|
||||
const themeService = <StandaloneThemeServiceImpl>StaticServices.standaloneThemeService.get();
|
||||
themeService.registerEditorContainer(document.body);
|
||||
return Colorizer.colorize(StaticServices.modeService.get(), text, languageId, options);
|
||||
}
|
||||
|
||||
@@ -255,6 +260,8 @@ export function colorize(text: string, languageId: string, options: IColorizerOp
|
||||
* Colorize a line in a model.
|
||||
*/
|
||||
export function colorizeModelLine(model: ITextModel, lineNumber: number, tabSize: number = 4): string {
|
||||
const themeService = <StandaloneThemeServiceImpl>StaticServices.standaloneThemeService.get();
|
||||
themeService.registerEditorContainer(document.body);
|
||||
return Colorizer.colorizeModelLine(model, lineNumber, tabSize);
|
||||
}
|
||||
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
import * as assert from 'assert';
|
||||
import { IEnvConfiguration } from 'vs/editor/common/config/commonEditorConfig';
|
||||
import { IEditorHoverOptions, EditorOption, ConfigurationChangedEvent } from 'vs/editor/common/config/editorOptions';
|
||||
import { IEditorHoverOptions, EditorOption, ConfigurationChangedEvent, IQuickSuggestionsOptions } from 'vs/editor/common/config/editorOptions';
|
||||
import { EditorZoom } from 'vs/editor/common/config/editorZoom';
|
||||
import { TestConfiguration } from 'vs/editor/test/common/mocks/testConfiguration';
|
||||
import { AccessibilitySupport } from 'vs/platform/accessibility/common/accessibility';
|
||||
@@ -201,4 +201,14 @@ suite('Common Editor Config', () => {
|
||||
config.updateOptions({ roundedSelection: false });
|
||||
assert.equal(event, null);
|
||||
});
|
||||
|
||||
test('issue #94931: Unable to open source file', () => {
|
||||
const config = new TestConfiguration({ quickSuggestions: null! });
|
||||
const actual = <Readonly<Required<IQuickSuggestionsOptions>>>config.options.get(EditorOption.quickSuggestions);
|
||||
assert.deepEqual(actual, {
|
||||
other: true,
|
||||
comments: false,
|
||||
strings: false
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user