mirror of
https://github.com/ckaczor/azuredatastudio.git
synced 2026-03-21 20:30:29 -04:00
Merge from vscode 3c6f6af7347d38e87bc6406024e8dcf9e9bce229 (#8962)
* Merge from vscode 3c6f6af7347d38e87bc6406024e8dcf9e9bce229 * skip failing tests * update mac build image
This commit is contained in:
committed by
Karl Burtram
parent
0eaee18dc4
commit
fefe1454de
@@ -110,7 +110,7 @@ export class LightBulbWidget extends Disposable implements IContentWidget {
|
||||
// showings until mouse is released
|
||||
this.hide();
|
||||
const monitor = new GlobalMouseMoveMonitor<IStandardMouseMoveEventData>();
|
||||
monitor.startMonitoring(e.buttons, standardMouseMoveMerger, () => { }, () => {
|
||||
monitor.startMonitoring(<HTMLElement>e.target, e.buttons, standardMouseMoveMerger, () => { }, () => {
|
||||
monitor.dispose();
|
||||
});
|
||||
}));
|
||||
|
||||
@@ -220,6 +220,43 @@ suite('CodeAction', () => {
|
||||
}
|
||||
});
|
||||
|
||||
test('getCodeActions no invoke a provider that has been excluded #84602', async function () {
|
||||
const baseType = CodeActionKind.Refactor;
|
||||
const subType = CodeActionKind.Refactor.append('sub');
|
||||
|
||||
disposables.add(modes.CodeActionProviderRegistry.register('fooLang', staticCodeActionProvider(
|
||||
{ title: 'a', kind: baseType.value }
|
||||
)));
|
||||
|
||||
let didInvoke = false;
|
||||
disposables.add(modes.CodeActionProviderRegistry.register('fooLang', new class implements modes.CodeActionProvider {
|
||||
|
||||
providedCodeActionKinds = [subType.value];
|
||||
|
||||
provideCodeActions(): modes.ProviderResult<modes.CodeActionList> {
|
||||
didInvoke = true;
|
||||
return {
|
||||
actions: [
|
||||
{ title: 'x', kind: subType.value }
|
||||
],
|
||||
dispose: () => { }
|
||||
};
|
||||
}
|
||||
}));
|
||||
|
||||
{
|
||||
const { validActions: actions } = await getCodeActions(model, new Range(1, 1, 2, 1), {
|
||||
type: modes.CodeActionTriggerType.Auto, filter: {
|
||||
include: baseType,
|
||||
excludes: [subType],
|
||||
}
|
||||
}, CancellationToken.None);
|
||||
assert.strictEqual(didInvoke, false);
|
||||
assert.equal(actions.length, 1);
|
||||
assert.strictEqual(actions[0].title, 'a');
|
||||
}
|
||||
});
|
||||
|
||||
test('getCodeActions should not invoke code action providers filtered out by providedCodeActionKinds', async function () {
|
||||
let wasInvoked = false;
|
||||
const provider = new class implements modes.CodeActionProvider {
|
||||
|
||||
@@ -58,6 +58,12 @@ export function mayIncludeActionsOfKind(filter: CodeActionFilter, providedKind:
|
||||
return false;
|
||||
}
|
||||
|
||||
if (filter.excludes) {
|
||||
if (filter.excludes.some(exclude => excludesAction(providedKind, exclude, filter.include))) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Don't return source actions unless they are explicitly requested
|
||||
if (!filter.includeSourceActions && CodeActionKind.Source.contains(providedKind)) {
|
||||
return false;
|
||||
@@ -77,10 +83,7 @@ export function filtersAction(filter: CodeActionFilter, action: CodeAction): boo
|
||||
}
|
||||
|
||||
if (filter.excludes) {
|
||||
if (actionKind && filter.excludes.some(exclude => {
|
||||
// Excludes are overwritten by includes
|
||||
return exclude.contains(actionKind) && (!filter.include || !filter.include.contains(actionKind));
|
||||
})) {
|
||||
if (actionKind && filter.excludes.some(exclude => excludesAction(actionKind, exclude, filter.include))) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -101,6 +104,17 @@ export function filtersAction(filter: CodeActionFilter, action: CodeAction): boo
|
||||
return true;
|
||||
}
|
||||
|
||||
function excludesAction(providedKind: CodeActionKind, exclude: CodeActionKind, include: CodeActionKind | undefined): boolean {
|
||||
if (!exclude.contains(providedKind)) {
|
||||
return false;
|
||||
}
|
||||
if (include && exclude.contains(include)) {
|
||||
// The include is more specific, don't filter out
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
export interface CodeActionTrigger {
|
||||
readonly type: CodeActionTriggerType;
|
||||
readonly filter?: CodeActionFilter;
|
||||
|
||||
@@ -18,7 +18,7 @@ import { ICommandService } from 'vs/platform/commands/common/commands';
|
||||
import { INotificationService } from 'vs/platform/notification/common/notification';
|
||||
import { ICodeLensCache } from 'vs/editor/contrib/codelens/codeLensCache';
|
||||
import { EditorOption } from 'vs/editor/common/config/editorOptions';
|
||||
import { createStyleSheet } from 'vs/base/browser/dom';
|
||||
import * as dom from 'vs/base/browser/dom';
|
||||
import { hash } from 'vs/base/common/hash';
|
||||
|
||||
export class CodeLensContribution implements IEditorContribution {
|
||||
@@ -65,7 +65,11 @@ export class CodeLensContribution implements IEditorContribution {
|
||||
this._onModelChange();
|
||||
|
||||
this._styleClassName = hash(this._editor.getId()).toString(16);
|
||||
this._styleElement = createStyleSheet();
|
||||
this._styleElement = dom.createStyleSheet(
|
||||
dom.isInShadowDOM(this._editor.getContainerDomNode())
|
||||
? this._editor.getContainerDomNode()
|
||||
: undefined
|
||||
);
|
||||
this._updateLensStyle();
|
||||
}
|
||||
|
||||
@@ -81,7 +85,13 @@ export class CodeLensContribution implements IEditorContribution {
|
||||
const fontInfo = options.get(EditorOption.fontInfo);
|
||||
const lineHeight = options.get(EditorOption.lineHeight);
|
||||
|
||||
const newStyle = `.monaco-editor .codelens-decoration.${this._styleClassName} { height: ${Math.round(lineHeight * 1.1)}px; line-height: ${lineHeight}px; font-size: ${Math.round(fontInfo.fontSize * 0.9)}px; padding-right: ${Math.round(fontInfo.fontSize * 0.45)}px;}`;
|
||||
|
||||
const height = Math.round(lineHeight * 1.1);
|
||||
const fontSize = Math.round(fontInfo.fontSize * 0.9);
|
||||
const newStyle = `
|
||||
.monaco-editor .codelens-decoration.${this._styleClassName} { height: ${height}px; line-height: ${lineHeight}px; font-size: ${fontSize}px; padding-right: ${Math.round(fontInfo.fontSize * 0.45)}px;}
|
||||
.monaco-editor .codelens-decoration.${this._styleClassName} > a > .codicon { line-height: ${lineHeight}px; font-size: ${fontSize}px; }
|
||||
`;
|
||||
this._styleElement.innerHTML = newStyle;
|
||||
}
|
||||
|
||||
|
||||
@@ -27,9 +27,8 @@
|
||||
}
|
||||
|
||||
.monaco-editor .codelens-decoration .codicon {
|
||||
line-height: inherit;
|
||||
font-size: 110%;
|
||||
vertical-align: inherit;
|
||||
vertical-align: middle;
|
||||
color: currentColor !important;
|
||||
}
|
||||
|
||||
.monaco-editor .codelens-decoration > a:hover .codicon::before {
|
||||
|
||||
@@ -192,7 +192,7 @@ export class ColorDetector extends Disposable implements IEditorContribution {
|
||||
border: 'solid 0.1em #eee'
|
||||
}
|
||||
}
|
||||
});
|
||||
}, undefined, this._editor);
|
||||
}
|
||||
|
||||
newDecorationsTypes[key] = true;
|
||||
|
||||
@@ -163,7 +163,7 @@ class SaturationBox extends Disposable {
|
||||
this.onDidChangePosition(e.offsetX, e.offsetY);
|
||||
}
|
||||
|
||||
this.monitor.startMonitoring(e.buttons, standardMouseMoveMerger, event => this.onDidChangePosition(event.posx - origin.left, event.posy - origin.top), () => null);
|
||||
this.monitor.startMonitoring(<HTMLElement>e.target, e.buttons, standardMouseMoveMerger, event => this.onDidChangePosition(event.posx - origin.left, event.posy - origin.top), () => null);
|
||||
|
||||
const mouseUpListener = dom.addDisposableGenericMouseUpListner(document, () => {
|
||||
this._onColorFlushed.fire();
|
||||
@@ -270,7 +270,7 @@ abstract class Strip extends Disposable {
|
||||
this.onDidChangeTop(e.offsetY);
|
||||
}
|
||||
|
||||
monitor.startMonitoring(e.buttons, standardMouseMoveMerger, event => this.onDidChangeTop(event.posy - origin.top), () => null);
|
||||
monitor.startMonitoring(<HTMLElement>e.target, e.buttons, standardMouseMoveMerger, event => this.onDidChangeTop(event.posy - origin.top), () => null);
|
||||
|
||||
const mouseUpListener = dom.addDisposableGenericMouseUpListner(document, () => {
|
||||
this._onColorFlushed.fire();
|
||||
|
||||
@@ -15,10 +15,12 @@ import { LanguageConfigurationRegistry } from 'vs/editor/common/modes/languageCo
|
||||
export class BlockCommentCommand implements ICommand {
|
||||
|
||||
private readonly _selection: Selection;
|
||||
private readonly _insertSpace: boolean;
|
||||
private _usedEndToken: string | null;
|
||||
|
||||
constructor(selection: Selection) {
|
||||
constructor(selection: Selection, insertSpace: boolean) {
|
||||
this._selection = selection;
|
||||
this._insertSpace = insertSpace;
|
||||
this._usedEndToken = null;
|
||||
}
|
||||
|
||||
@@ -53,7 +55,7 @@ export class BlockCommentCommand implements ICommand {
|
||||
return true;
|
||||
}
|
||||
|
||||
private _createOperationsForBlockComment(selection: Range, startToken: string, endToken: string, model: ITextModel, builder: IEditOperationBuilder): void {
|
||||
private _createOperationsForBlockComment(selection: Range, startToken: string, endToken: string, insertSpace: boolean, model: ITextModel, builder: IEditOperationBuilder): void {
|
||||
const startLineNumber = selection.startLineNumber;
|
||||
const startColumn = selection.startColumn;
|
||||
const endLineNumber = selection.endLineNumber;
|
||||
@@ -91,25 +93,21 @@ export class BlockCommentCommand implements ICommand {
|
||||
|
||||
if (startTokenIndex !== -1 && endTokenIndex !== -1) {
|
||||
// Consider spaces as part of the comment tokens
|
||||
if (startTokenIndex + startToken.length < startLineText.length) {
|
||||
if (startLineText.charCodeAt(startTokenIndex + startToken.length) === CharCode.Space) {
|
||||
// Pretend the start token contains a trailing space
|
||||
startToken = startToken + ' ';
|
||||
}
|
||||
if (insertSpace && startTokenIndex + startToken.length < startLineText.length && startLineText.charCodeAt(startTokenIndex + startToken.length) === CharCode.Space) {
|
||||
// Pretend the start token contains a trailing space
|
||||
startToken = startToken + ' ';
|
||||
}
|
||||
|
||||
if (endTokenIndex > 0) {
|
||||
if (endLineText.charCodeAt(endTokenIndex - 1) === CharCode.Space) {
|
||||
// Pretend the end token contains a leading space
|
||||
endToken = ' ' + endToken;
|
||||
endTokenIndex -= 1;
|
||||
}
|
||||
if (insertSpace && endTokenIndex > 0 && endLineText.charCodeAt(endTokenIndex - 1) === CharCode.Space) {
|
||||
// Pretend the end token contains a leading space
|
||||
endToken = ' ' + endToken;
|
||||
endTokenIndex -= 1;
|
||||
}
|
||||
ops = BlockCommentCommand._createRemoveBlockCommentOperations(
|
||||
new Range(startLineNumber, startTokenIndex + startToken.length + 1, endLineNumber, endTokenIndex + 1), startToken, endToken
|
||||
);
|
||||
} else {
|
||||
ops = BlockCommentCommand._createAddBlockCommentOperations(selection, startToken, endToken);
|
||||
ops = BlockCommentCommand._createAddBlockCommentOperations(selection, startToken, endToken, this._insertSpace);
|
||||
this._usedEndToken = ops.length === 1 ? endToken : null;
|
||||
}
|
||||
|
||||
@@ -144,15 +142,15 @@ export class BlockCommentCommand implements ICommand {
|
||||
return res;
|
||||
}
|
||||
|
||||
public static _createAddBlockCommentOperations(r: Range, startToken: string, endToken: string): IIdentifiedSingleEditOperation[] {
|
||||
public static _createAddBlockCommentOperations(r: Range, startToken: string, endToken: string, insertSpace: boolean): IIdentifiedSingleEditOperation[] {
|
||||
let res: IIdentifiedSingleEditOperation[] = [];
|
||||
|
||||
if (!Range.isEmpty(r)) {
|
||||
// Insert block comment start
|
||||
res.push(EditOperation.insert(new Position(r.startLineNumber, r.startColumn), startToken + ' '));
|
||||
res.push(EditOperation.insert(new Position(r.startLineNumber, r.startColumn), startToken + (insertSpace ? ' ' : '')));
|
||||
|
||||
// Insert block comment end
|
||||
res.push(EditOperation.insert(new Position(r.endLineNumber, r.endColumn), ' ' + endToken));
|
||||
res.push(EditOperation.insert(new Position(r.endLineNumber, r.endColumn), (insertSpace ? ' ' : '') + endToken));
|
||||
} else {
|
||||
// Insert both continuously
|
||||
res.push(EditOperation.replace(new Range(
|
||||
@@ -176,7 +174,7 @@ export class BlockCommentCommand implements ICommand {
|
||||
return;
|
||||
}
|
||||
|
||||
this._createOperationsForBlockComment(this._selection, config.blockCommentStartToken, config.blockCommentEndToken, model, builder);
|
||||
this._createOperationsForBlockComment(this._selection, config.blockCommentStartToken, config.blockCommentEndToken, this._insertSpace, model, builder);
|
||||
}
|
||||
|
||||
public computeCursorState(model: ITextModel, helper: ICursorStateComputerData): Selection {
|
||||
|
||||
@@ -12,6 +12,7 @@ import { EditorContextKeys } from 'vs/editor/common/editorContextKeys';
|
||||
import { BlockCommentCommand } from 'vs/editor/contrib/comment/blockCommentCommand';
|
||||
import { LineCommentCommand, Type } from 'vs/editor/contrib/comment/lineCommentCommand';
|
||||
// import { MenuId } from 'vs/platform/actions/common/actions';
|
||||
import { EditorOption } from 'vs/editor/common/config/editorOptions';
|
||||
import { KeybindingWeight } from 'vs/platform/keybinding/common/keybindingsRegistry';
|
||||
|
||||
abstract class CommentLineAction extends EditorAction {
|
||||
@@ -28,13 +29,14 @@ abstract class CommentLineAction extends EditorAction {
|
||||
return;
|
||||
}
|
||||
|
||||
let model = editor.getModel();
|
||||
let commands: ICommand[] = [];
|
||||
let selections = editor.getSelections();
|
||||
let opts = model.getOptions();
|
||||
const model = editor.getModel();
|
||||
const commands: ICommand[] = [];
|
||||
const selections = editor.getSelections();
|
||||
const modelOptions = model.getOptions();
|
||||
const commentsOptions = editor.getOption(EditorOption.comments);
|
||||
|
||||
for (const selection of selections) {
|
||||
commands.push(new LineCommentCommand(selection, opts.tabSize, this._type));
|
||||
commands.push(new LineCommentCommand(selection, modelOptions.tabSize, this._type, commentsOptions.insertSpace));
|
||||
}
|
||||
|
||||
editor.pushUndoStop();
|
||||
@@ -126,10 +128,11 @@ class BlockCommentAction extends EditorAction {
|
||||
return;
|
||||
}
|
||||
|
||||
let commands: ICommand[] = [];
|
||||
let selections = editor.getSelections();
|
||||
const commentsOptions = editor.getOption(EditorOption.comments);
|
||||
const commands: ICommand[] = [];
|
||||
const selections = editor.getSelections();
|
||||
for (const selection of selections) {
|
||||
commands.push(new BlockCommentCommand(selection));
|
||||
commands.push(new BlockCommentCommand(selection, commentsOptions.insertSpace));
|
||||
}
|
||||
|
||||
editor.pushUndoStop();
|
||||
|
||||
@@ -50,17 +50,19 @@ export const enum Type {
|
||||
export class LineCommentCommand implements ICommand {
|
||||
|
||||
private readonly _selection: Selection;
|
||||
private readonly _tabSize: number;
|
||||
private readonly _type: Type;
|
||||
private readonly _insertSpace: boolean;
|
||||
private _selectionId: string | null;
|
||||
private _deltaColumn: number;
|
||||
private _moveEndPositionDown: boolean;
|
||||
private readonly _tabSize: number;
|
||||
private readonly _type: Type;
|
||||
|
||||
constructor(selection: Selection, tabSize: number, type: Type) {
|
||||
constructor(selection: Selection, tabSize: number, type: Type, insertSpace: boolean) {
|
||||
this._selection = selection;
|
||||
this._selectionId = null;
|
||||
this._tabSize = tabSize;
|
||||
this._type = type;
|
||||
this._insertSpace = insertSpace;
|
||||
this._selectionId = null;
|
||||
this._deltaColumn = 0;
|
||||
this._moveEndPositionDown = false;
|
||||
}
|
||||
@@ -98,7 +100,7 @@ export class LineCommentCommand implements ICommand {
|
||||
* Analyze lines and decide which lines are relevant and what the toggle should do.
|
||||
* Also, build up several offsets and lengths useful in the generation of editor operations.
|
||||
*/
|
||||
public static _analyzeLines(type: Type, model: ISimpleModel, lines: ILinePreflightData[], startLineNumber: number): IPreflightData {
|
||||
public static _analyzeLines(type: Type, insertSpace: boolean, model: ISimpleModel, lines: ILinePreflightData[], startLineNumber: number): IPreflightData {
|
||||
let onlyWhitespaceLines = true;
|
||||
|
||||
let shouldRemoveComments: boolean;
|
||||
@@ -145,7 +147,8 @@ export class LineCommentCommand implements ICommand {
|
||||
}
|
||||
}
|
||||
|
||||
if (shouldRemoveComments) {
|
||||
if (shouldRemoveComments && insertSpace) {
|
||||
// Remove a following space if present
|
||||
const commentStrEndOffset = lineContentStartOffset + lineData.commentStrLength;
|
||||
if (commentStrEndOffset < lineContent.length && lineContent.charCodeAt(commentStrEndOffset) === CharCode.Space) {
|
||||
lineData.commentStrLength += 1;
|
||||
@@ -173,7 +176,7 @@ export class LineCommentCommand implements ICommand {
|
||||
/**
|
||||
* Analyze all lines and decide exactly what to do => not supported | insert line comments | remove line comments
|
||||
*/
|
||||
public static _gatherPreflightData(type: Type, model: ITextModel, startLineNumber: number, endLineNumber: number): IPreflightData {
|
||||
public static _gatherPreflightData(type: Type, insertSpace: boolean, model: ITextModel, startLineNumber: number, endLineNumber: number): IPreflightData {
|
||||
const lines = LineCommentCommand._gatherPreflightCommentStrings(model, startLineNumber, endLineNumber);
|
||||
if (lines === null) {
|
||||
return {
|
||||
@@ -181,7 +184,7 @@ export class LineCommentCommand implements ICommand {
|
||||
};
|
||||
}
|
||||
|
||||
return LineCommentCommand._analyzeLines(type, model, lines, startLineNumber);
|
||||
return LineCommentCommand._analyzeLines(type, insertSpace, model, lines, startLineNumber);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -195,7 +198,7 @@ export class LineCommentCommand implements ICommand {
|
||||
ops = LineCommentCommand._createRemoveLineCommentsOperations(data.lines, s.startLineNumber);
|
||||
} else {
|
||||
LineCommentCommand._normalizeInsertionPoint(model, data.lines, s.startLineNumber, this._tabSize);
|
||||
ops = LineCommentCommand._createAddLineCommentsOperations(data.lines, s.startLineNumber);
|
||||
ops = this._createAddLineCommentsOperations(data.lines, s.startLineNumber);
|
||||
}
|
||||
|
||||
const cursorPosition = new Position(s.positionLineNumber, s.positionColumn);
|
||||
@@ -288,11 +291,17 @@ export class LineCommentCommand implements ICommand {
|
||||
firstNonWhitespaceIndex = lineContent.length;
|
||||
}
|
||||
ops = BlockCommentCommand._createAddBlockCommentOperations(
|
||||
new Range(s.startLineNumber, firstNonWhitespaceIndex + 1, s.startLineNumber, lineContent.length + 1), startToken, endToken
|
||||
new Range(s.startLineNumber, firstNonWhitespaceIndex + 1, s.startLineNumber, lineContent.length + 1),
|
||||
startToken,
|
||||
endToken,
|
||||
this._insertSpace
|
||||
);
|
||||
} else {
|
||||
ops = BlockCommentCommand._createAddBlockCommentOperations(
|
||||
new Range(s.startLineNumber, model.getLineFirstNonWhitespaceColumn(s.startLineNumber), s.endLineNumber, model.getLineMaxColumn(s.endLineNumber)), startToken, endToken
|
||||
new Range(s.startLineNumber, model.getLineFirstNonWhitespaceColumn(s.startLineNumber), s.endLineNumber, model.getLineMaxColumn(s.endLineNumber)),
|
||||
startToken,
|
||||
endToken,
|
||||
this._insertSpace
|
||||
);
|
||||
}
|
||||
|
||||
@@ -317,7 +326,7 @@ export class LineCommentCommand implements ICommand {
|
||||
s = s.setEndPosition(s.endLineNumber - 1, model.getLineMaxColumn(s.endLineNumber - 1));
|
||||
}
|
||||
|
||||
const data = LineCommentCommand._gatherPreflightData(this._type, model, s.startLineNumber, s.endLineNumber);
|
||||
const data = LineCommentCommand._gatherPreflightData(this._type, this._insertSpace, model, s.startLineNumber, s.endLineNumber);
|
||||
if (data.supported) {
|
||||
return this._executeLineComments(model, builder, data, s);
|
||||
}
|
||||
@@ -365,8 +374,10 @@ export class LineCommentCommand implements ICommand {
|
||||
/**
|
||||
* Generate edit operations in the add line comment case
|
||||
*/
|
||||
public static _createAddLineCommentsOperations(lines: ILinePreflightData[], startLineNumber: number): IIdentifiedSingleEditOperation[] {
|
||||
private _createAddLineCommentsOperations(lines: ILinePreflightData[], startLineNumber: number): IIdentifiedSingleEditOperation[] {
|
||||
let res: IIdentifiedSingleEditOperation[] = [];
|
||||
const afterCommentStr = this._insertSpace ? ' ' : '';
|
||||
|
||||
|
||||
for (let i = 0, len = lines.length; i < len; i++) {
|
||||
const lineData = lines[i];
|
||||
@@ -375,7 +386,7 @@ export class LineCommentCommand implements ICommand {
|
||||
continue;
|
||||
}
|
||||
|
||||
res.push(EditOperation.insert(new Position(startLineNumber + i, lineData.commentStrOffset + 1), lineData.commentStr + ' '));
|
||||
res.push(EditOperation.insert(new Position(startLineNumber + i, lineData.commentStrOffset + 1), lineData.commentStr + afterCommentStr));
|
||||
}
|
||||
|
||||
return res;
|
||||
|
||||
@@ -9,7 +9,7 @@ import { CommentMode } from 'vs/editor/test/common/commentMode';
|
||||
|
||||
function testBlockCommentCommand(lines: string[], selection: Selection, expectedLines: string[], expectedSelection: Selection): void {
|
||||
let mode = new CommentMode({ lineComment: '!@#', blockComment: ['<0', '0>'] });
|
||||
testCommand(lines, mode.getLanguageIdentifier(), selection, (sel) => new BlockCommentCommand(sel), expectedLines, expectedSelection);
|
||||
testCommand(lines, mode.getLanguageIdentifier(), selection, (sel) => new BlockCommentCommand(sel, true), expectedLines, expectedSelection);
|
||||
mode.dispose();
|
||||
}
|
||||
|
||||
@@ -468,4 +468,45 @@ suite('Editor Contrib - Block Comment Command', () => {
|
||||
new Selection(1, 1, 1, 1)
|
||||
);
|
||||
});
|
||||
|
||||
test('', () => {
|
||||
});
|
||||
|
||||
test('insertSpace false', () => {
|
||||
function testLineCommentCommand(lines: string[], selection: Selection, expectedLines: string[], expectedSelection: Selection): void {
|
||||
let mode = new CommentMode({ lineComment: '!@#', blockComment: ['<0', '0>'] });
|
||||
testCommand(lines, mode.getLanguageIdentifier(), selection, (sel) => new BlockCommentCommand(sel, false), expectedLines, expectedSelection);
|
||||
mode.dispose();
|
||||
}
|
||||
|
||||
testLineCommentCommand(
|
||||
[
|
||||
'some text'
|
||||
],
|
||||
new Selection(1, 1, 1, 5),
|
||||
[
|
||||
'<0some0> text'
|
||||
],
|
||||
new Selection(1, 3, 1, 7)
|
||||
);
|
||||
});
|
||||
|
||||
test('insertSpace false does not remove space', () => {
|
||||
function testLineCommentCommand(lines: string[], selection: Selection, expectedLines: string[], expectedSelection: Selection): void {
|
||||
let mode = new CommentMode({ lineComment: '!@#', blockComment: ['<0', '0>'] });
|
||||
testCommand(lines, mode.getLanguageIdentifier(), selection, (sel) => new BlockCommentCommand(sel, false), expectedLines, expectedSelection);
|
||||
mode.dispose();
|
||||
}
|
||||
|
||||
testLineCommentCommand(
|
||||
[
|
||||
'<0 some 0> text'
|
||||
],
|
||||
new Selection(1, 4, 1, 8),
|
||||
[
|
||||
' some text'
|
||||
],
|
||||
new Selection(1, 1, 1, 7)
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import * as assert from 'assert';
|
||||
import { Selection } from 'vs/editor/common/core/selection';
|
||||
import { TokenizationResult2 } from 'vs/editor/common/core/token';
|
||||
@@ -18,13 +19,13 @@ suite('Editor Contrib - Line Comment Command', () => {
|
||||
|
||||
function testLineCommentCommand(lines: string[], selection: Selection, expectedLines: string[], expectedSelection: Selection): void {
|
||||
let mode = new CommentMode({ lineComment: '!@#', blockComment: ['<!@#', '#@!>'] });
|
||||
testCommand(lines, mode.getLanguageIdentifier(), selection, (sel) => new LineCommentCommand(sel, 4, Type.Toggle), expectedLines, expectedSelection);
|
||||
testCommand(lines, mode.getLanguageIdentifier(), selection, (sel) => new LineCommentCommand(sel, 4, Type.Toggle, true), expectedLines, expectedSelection);
|
||||
mode.dispose();
|
||||
}
|
||||
|
||||
function testAddLineCommentCommand(lines: string[], selection: Selection, expectedLines: string[], expectedSelection: Selection): void {
|
||||
let mode = new CommentMode({ lineComment: '!@#', blockComment: ['<!@#', '#@!>'] });
|
||||
testCommand(lines, mode.getLanguageIdentifier(), selection, (sel) => new LineCommentCommand(sel, 4, Type.ForceAdd), expectedLines, expectedSelection);
|
||||
testCommand(lines, mode.getLanguageIdentifier(), selection, (sel) => new LineCommentCommand(sel, 4, Type.ForceAdd, true), expectedLines, expectedSelection);
|
||||
mode.dispose();
|
||||
}
|
||||
|
||||
@@ -46,7 +47,7 @@ suite('Editor Contrib - Line Comment Command', () => {
|
||||
test('case insensitive', function () {
|
||||
function testLineCommentCommand(lines: string[], selection: Selection, expectedLines: string[], expectedSelection: Selection): void {
|
||||
let mode = new CommentMode({ lineComment: 'rem' });
|
||||
testCommand(lines, mode.getLanguageIdentifier(), selection, (sel) => new LineCommentCommand(sel, 4, Type.Toggle), expectedLines, expectedSelection);
|
||||
testCommand(lines, mode.getLanguageIdentifier(), selection, (sel) => new LineCommentCommand(sel, 4, Type.Toggle, true), expectedLines, expectedSelection);
|
||||
mode.dispose();
|
||||
}
|
||||
|
||||
@@ -85,7 +86,7 @@ suite('Editor Contrib - Line Comment Command', () => {
|
||||
test('_analyzeLines', () => {
|
||||
let r: IPreflightData;
|
||||
|
||||
r = LineCommentCommand._analyzeLines(Type.Toggle, createSimpleModel([
|
||||
r = LineCommentCommand._analyzeLines(Type.Toggle, true, createSimpleModel([
|
||||
'\t\t',
|
||||
' ',
|
||||
' c',
|
||||
@@ -116,7 +117,7 @@ suite('Editor Contrib - Line Comment Command', () => {
|
||||
assert.equal(r.lines[3].commentStrOffset, 2);
|
||||
|
||||
|
||||
r = LineCommentCommand._analyzeLines(Type.Toggle, createSimpleModel([
|
||||
r = LineCommentCommand._analyzeLines(Type.Toggle, true, createSimpleModel([
|
||||
'\t\t',
|
||||
' rem ',
|
||||
' !@# c',
|
||||
@@ -626,13 +627,51 @@ suite('Editor Contrib - Line Comment Command', () => {
|
||||
new Selection(2, 11, 1, 1)
|
||||
);
|
||||
});
|
||||
|
||||
test('insertSpace false', () => {
|
||||
function testLineCommentCommand(lines: string[], selection: Selection, expectedLines: string[], expectedSelection: Selection): void {
|
||||
let mode = new CommentMode({ lineComment: '!@#' });
|
||||
testCommand(lines, mode.getLanguageIdentifier(), selection, (sel) => new LineCommentCommand(sel, 4, Type.Toggle, false), expectedLines, expectedSelection);
|
||||
mode.dispose();
|
||||
}
|
||||
|
||||
testLineCommentCommand(
|
||||
[
|
||||
'some text'
|
||||
],
|
||||
new Selection(1, 1, 1, 1),
|
||||
[
|
||||
'!@#some text'
|
||||
],
|
||||
new Selection(1, 4, 1, 4)
|
||||
);
|
||||
});
|
||||
|
||||
test('insertSpace false does not remove space', () => {
|
||||
function testLineCommentCommand(lines: string[], selection: Selection, expectedLines: string[], expectedSelection: Selection): void {
|
||||
let mode = new CommentMode({ lineComment: '!@#' });
|
||||
testCommand(lines, mode.getLanguageIdentifier(), selection, (sel) => new LineCommentCommand(sel, 4, Type.Toggle, false), expectedLines, expectedSelection);
|
||||
mode.dispose();
|
||||
}
|
||||
|
||||
testLineCommentCommand(
|
||||
[
|
||||
'!@# some text'
|
||||
],
|
||||
new Selection(1, 1, 1, 1),
|
||||
[
|
||||
' some text'
|
||||
],
|
||||
new Selection(1, 1, 1, 1)
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
suite('Editor Contrib - Line Comment As Block Comment', () => {
|
||||
|
||||
function testLineCommentCommand(lines: string[], selection: Selection, expectedLines: string[], expectedSelection: Selection): void {
|
||||
let mode = new CommentMode({ lineComment: '', blockComment: ['(', ')'] });
|
||||
testCommand(lines, mode.getLanguageIdentifier(), selection, (sel) => new LineCommentCommand(sel, 4, Type.Toggle), expectedLines, expectedSelection);
|
||||
testCommand(lines, mode.getLanguageIdentifier(), selection, (sel) => new LineCommentCommand(sel, 4, Type.Toggle, true), expectedLines, expectedSelection);
|
||||
mode.dispose();
|
||||
}
|
||||
|
||||
@@ -743,7 +782,7 @@ suite('Editor Contrib - Line Comment As Block Comment', () => {
|
||||
suite('Editor Contrib - Line Comment As Block Comment 2', () => {
|
||||
function testLineCommentCommand(lines: string[], selection: Selection, expectedLines: string[], expectedSelection: Selection): void {
|
||||
let mode = new CommentMode({ lineComment: null, blockComment: ['<!@#', '#@!>'] });
|
||||
testCommand(lines, mode.getLanguageIdentifier(), selection, (sel) => new LineCommentCommand(sel, 4, Type.Toggle), expectedLines, expectedSelection);
|
||||
testCommand(lines, mode.getLanguageIdentifier(), selection, (sel) => new LineCommentCommand(sel, 4, Type.Toggle, true), expectedLines, expectedSelection);
|
||||
mode.dispose();
|
||||
}
|
||||
|
||||
@@ -984,7 +1023,7 @@ suite('Editor Contrib - Line Comment in mixed modes', () => {
|
||||
lines,
|
||||
outerMode.getLanguageIdentifier(),
|
||||
selection,
|
||||
(sel) => new LineCommentCommand(sel, 4, Type.Toggle),
|
||||
(sel) => new LineCommentCommand(sel, 4, Type.Toggle, true),
|
||||
expectedLines,
|
||||
expectedSelection,
|
||||
true
|
||||
|
||||
@@ -9,7 +9,7 @@ import { Disposable } from 'vs/base/common/lifecycle';
|
||||
import { ICodeEditor } from 'vs/editor/browser/editorBrowser';
|
||||
import { EditorAction, ServicesAccessor, registerEditorAction, registerEditorContribution } from 'vs/editor/browser/editorExtensions';
|
||||
import { Selection } from 'vs/editor/common/core/selection';
|
||||
import { IEditorContribution, ScrollType } from 'vs/editor/common/editorCommon';
|
||||
import { IEditorContribution } from 'vs/editor/common/editorCommon';
|
||||
import { EditorContextKeys } from 'vs/editor/common/editorContextKeys';
|
||||
import { KeybindingWeight } from 'vs/platform/keybinding/common/keybindingsRegistry';
|
||||
|
||||
@@ -35,6 +35,14 @@ class CursorState {
|
||||
}
|
||||
}
|
||||
|
||||
class StackElement {
|
||||
constructor(
|
||||
public readonly cursorState: CursorState,
|
||||
public readonly scrollTop: number,
|
||||
public readonly scrollLeft: number
|
||||
) { }
|
||||
}
|
||||
|
||||
export class CursorUndoRedoController extends Disposable implements IEditorContribution {
|
||||
|
||||
public static readonly ID = 'editor.contrib.cursorUndoRedoController';
|
||||
@@ -46,8 +54,8 @@ export class CursorUndoRedoController extends Disposable implements IEditorContr
|
||||
private readonly _editor: ICodeEditor;
|
||||
private _isCursorUndoRedo: boolean;
|
||||
|
||||
private _undoStack: CursorState[];
|
||||
private _redoStack: CursorState[];
|
||||
private _undoStack: StackElement[];
|
||||
private _redoStack: StackElement[];
|
||||
|
||||
constructor(editor: ICodeEditor) {
|
||||
super();
|
||||
@@ -76,9 +84,9 @@ export class CursorUndoRedoController extends Disposable implements IEditorContr
|
||||
return;
|
||||
}
|
||||
const prevState = new CursorState(e.oldSelections);
|
||||
const isEqualToLastUndoStack = (this._undoStack.length > 0 && this._undoStack[this._undoStack.length - 1].equals(prevState));
|
||||
const isEqualToLastUndoStack = (this._undoStack.length > 0 && this._undoStack[this._undoStack.length - 1].cursorState.equals(prevState));
|
||||
if (!isEqualToLastUndoStack) {
|
||||
this._undoStack.push(prevState);
|
||||
this._undoStack.push(new StackElement(prevState, editor.getScrollTop(), editor.getScrollLeft()));
|
||||
this._redoStack = [];
|
||||
if (this._undoStack.length > 50) {
|
||||
// keep the cursor undo stack bounded
|
||||
@@ -93,7 +101,7 @@ export class CursorUndoRedoController extends Disposable implements IEditorContr
|
||||
return;
|
||||
}
|
||||
|
||||
this._redoStack.push(new CursorState(this._editor.getSelections()));
|
||||
this._redoStack.push(new StackElement(new CursorState(this._editor.getSelections()), this._editor.getScrollTop(), this._editor.getScrollLeft()));
|
||||
this._applyState(this._undoStack.pop()!);
|
||||
}
|
||||
|
||||
@@ -102,14 +110,17 @@ export class CursorUndoRedoController extends Disposable implements IEditorContr
|
||||
return;
|
||||
}
|
||||
|
||||
this._undoStack.push(new CursorState(this._editor.getSelections()));
|
||||
this._undoStack.push(new StackElement(new CursorState(this._editor.getSelections()), this._editor.getScrollTop(), this._editor.getScrollLeft()));
|
||||
this._applyState(this._redoStack.pop()!);
|
||||
}
|
||||
|
||||
private _applyState(state: CursorState): void {
|
||||
private _applyState(stackElement: StackElement): void {
|
||||
this._isCursorUndoRedo = true;
|
||||
this._editor.setSelections(state.selections);
|
||||
this._editor.revealRangeInCenterIfOutsideViewport(state.selections[0], ScrollType.Smooth);
|
||||
this._editor.setSelections(stackElement.cursorState.selections);
|
||||
this._editor.setScrollPosition({
|
||||
scrollTop: stackElement.scrollTop,
|
||||
scrollLeft: stackElement.scrollLeft
|
||||
});
|
||||
this._isCursorUndoRedo = false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -191,7 +191,7 @@ class FormatOnPaste implements IEditorContribution {
|
||||
return;
|
||||
}
|
||||
|
||||
this._callOnModel.add(this.editor.onDidPaste(range => this._trigger(range)));
|
||||
this._callOnModel.add(this.editor.onDidPaste(({ range }) => this._trigger(range)));
|
||||
}
|
||||
|
||||
private _trigger(range: Range): void {
|
||||
|
||||
@@ -27,6 +27,7 @@ import { MenuRegistry, MenuId } from 'vs/platform/actions/common/actions';
|
||||
import { Action } from 'vs/base/common/actions';
|
||||
import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding';
|
||||
import { isEqual } from 'vs/base/common/resources';
|
||||
import { IOpenerService } from 'vs/platform/opener/common/opener';
|
||||
|
||||
class MarkerModel {
|
||||
|
||||
@@ -209,7 +210,8 @@ export class MarkerController implements IEditorContribution {
|
||||
@IContextKeyService private readonly _contextKeyService: IContextKeyService,
|
||||
@IThemeService private readonly _themeService: IThemeService,
|
||||
@ICodeEditorService private readonly _editorService: ICodeEditorService,
|
||||
@IKeybindingService private readonly _keybindingService: IKeybindingService
|
||||
@IKeybindingService private readonly _keybindingService: IKeybindingService,
|
||||
@IOpenerService private readonly _openerService: IOpenerService
|
||||
) {
|
||||
this._editor = editor;
|
||||
this._widgetVisible = CONTEXT_MARKERS_NAVIGATION_VISIBLE.bindTo(this._contextKeyService);
|
||||
@@ -243,7 +245,7 @@ export class MarkerController implements IEditorContribution {
|
||||
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); } })
|
||||
];
|
||||
this._widget = new MarkerNavigationWidget(this._editor, actions, this._themeService);
|
||||
this._widget = new MarkerNavigationWidget(this._editor, actions, this._themeService, this._openerService);
|
||||
this._widgetVisible.set(true);
|
||||
this._widget.onDidClose(() => this.closeMarkersNavigation(), this, this._disposeOnClose);
|
||||
|
||||
|
||||
@@ -26,6 +26,7 @@ import { IAction } from 'vs/base/common/actions';
|
||||
import { IActionBarOptions, ActionsOrientation } from 'vs/base/browser/ui/actionbar/actionbar';
|
||||
import { SeverityIcon } from 'vs/platform/severityIcon/common/severityIcon';
|
||||
import { EditorOption } from 'vs/editor/common/config/editorOptions';
|
||||
import { IOpenerService } from 'vs/platform/opener/common/opener';
|
||||
|
||||
class MessageWidget {
|
||||
|
||||
@@ -39,7 +40,14 @@ class MessageWidget {
|
||||
private readonly _relatedDiagnostics = new WeakMap<HTMLElement, IRelatedInformation>();
|
||||
private readonly _disposables: DisposableStore = new DisposableStore();
|
||||
|
||||
constructor(parent: HTMLElement, editor: ICodeEditor, onRelatedInformation: (related: IRelatedInformation) => void) {
|
||||
private _codeLink?: HTMLElement;
|
||||
|
||||
constructor(
|
||||
parent: HTMLElement,
|
||||
editor: ICodeEditor,
|
||||
onRelatedInformation: (related: IRelatedInformation) => void,
|
||||
private readonly _openerService: IOpenerService,
|
||||
) {
|
||||
this._editor = editor;
|
||||
|
||||
const domNode = document.createElement('div');
|
||||
@@ -81,12 +89,20 @@ class MessageWidget {
|
||||
}
|
||||
|
||||
update({ source, message, relatedInformation, code }: IMarker): void {
|
||||
let sourceAndCodeLength = (source?.length || 0) + '()'.length;
|
||||
if (code) {
|
||||
if (typeof code === 'string') {
|
||||
sourceAndCodeLength += code.length;
|
||||
} else {
|
||||
sourceAndCodeLength += code.value.length;
|
||||
}
|
||||
}
|
||||
|
||||
const lines = message.split(/\r\n|\r|\n/g);
|
||||
this._lines = lines.length;
|
||||
this._longestLineLength = 0;
|
||||
for (const line of lines) {
|
||||
this._longestLineLength = Math.max(line.length, this._longestLineLength);
|
||||
this._longestLineLength = Math.max(line.length + sourceAndCodeLength, this._longestLineLength);
|
||||
}
|
||||
|
||||
dom.clearNode(this._messageBlock);
|
||||
@@ -111,10 +127,25 @@ class MessageWidget {
|
||||
detailsElement.appendChild(sourceElement);
|
||||
}
|
||||
if (code) {
|
||||
const codeElement = document.createElement('span');
|
||||
codeElement.innerText = `(${code})`;
|
||||
dom.addClass(codeElement, 'code');
|
||||
detailsElement.appendChild(codeElement);
|
||||
if (typeof code === 'string') {
|
||||
const codeElement = document.createElement('span');
|
||||
codeElement.innerText = `(${code})`;
|
||||
dom.addClass(codeElement, 'code');
|
||||
detailsElement.appendChild(codeElement);
|
||||
} else {
|
||||
this._codeLink = dom.$('a.code-link');
|
||||
this._codeLink.setAttribute('href', `${code.link.toString()}`);
|
||||
|
||||
this._codeLink.onclick = (e) => {
|
||||
this._openerService.open(code.link);
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
};
|
||||
|
||||
const codeElement = dom.append(this._codeLink, dom.$('span'));
|
||||
codeElement.innerText = code.value;
|
||||
detailsElement.appendChild(this._codeLink);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -180,7 +211,8 @@ export class MarkerNavigationWidget extends PeekViewWidget {
|
||||
constructor(
|
||||
editor: ICodeEditor,
|
||||
private readonly actions: ReadonlyArray<IAction>,
|
||||
private readonly _themeService: IThemeService
|
||||
private readonly _themeService: IThemeService,
|
||||
private readonly _openerService: IOpenerService
|
||||
) {
|
||||
super(editor, { showArrow: true, showFrame: true, isAccessible: true });
|
||||
this._severity = MarkerSeverity.Warning;
|
||||
@@ -250,7 +282,7 @@ export class MarkerNavigationWidget extends PeekViewWidget {
|
||||
this._container = document.createElement('div');
|
||||
container.appendChild(this._container);
|
||||
|
||||
this._message = new MessageWidget(this._container, this.editor, related => this._onDidSelectRelatedInformation.fire(related));
|
||||
this._message = new MessageWidget(this._container, this.editor, related => this._onDidSelectRelatedInformation.fire(related), this._openerService);
|
||||
this._disposables.add(this._message);
|
||||
}
|
||||
|
||||
@@ -329,8 +361,9 @@ export const editorMarkerNavigationInfo = registerColor('editorMarkerNavigationI
|
||||
export const editorMarkerNavigationBackground = registerColor('editorMarkerNavigation.background', { dark: '#2D2D30', light: Color.white, hc: '#0C141F' }, nls.localize('editorMarkerNavigationBackground', 'Editor marker navigation widget background.'));
|
||||
|
||||
registerThemingParticipant((theme, collector) => {
|
||||
const link = theme.getColor(textLinkForeground);
|
||||
if (link) {
|
||||
collector.addRule(`.monaco-editor .marker-widget a { color: ${link}; }`);
|
||||
const linkFg = theme.getColor(textLinkForeground);
|
||||
if (linkFg) {
|
||||
collector.addRule(`.monaco-editor .marker-widget a { color: ${linkFg}; }`);
|
||||
collector.addRule(`.monaco-editor .marker-widget a.code-link span:hover { color: ${linkFg}; }`);
|
||||
}
|
||||
});
|
||||
|
||||
@@ -45,10 +45,27 @@
|
||||
}
|
||||
|
||||
.monaco-editor .marker-widget .descriptioncontainer .message .source,
|
||||
.monaco-editor .marker-widget .descriptioncontainer .message .code {
|
||||
.monaco-editor .marker-widget .descriptioncontainer .message span.code {
|
||||
opacity: 0.6;
|
||||
}
|
||||
|
||||
.monaco-editor .marker-widget .descriptioncontainer .message a.code-link {
|
||||
opacity: 0.6;
|
||||
color: inherit;
|
||||
}
|
||||
.monaco-editor .marker-widget .descriptioncontainer .message a.code-link:before {
|
||||
content: '(';
|
||||
}
|
||||
.monaco-editor .marker-widget .descriptioncontainer .message a.code-link:after {
|
||||
content: ')';
|
||||
}
|
||||
.monaco-editor .marker-widget .descriptioncontainer .message a.code-link > span {
|
||||
text-decoration: underline;
|
||||
/** Hack to force underline to show **/
|
||||
border-bottom: 1px solid transparent;
|
||||
text-underline-position: under;
|
||||
}
|
||||
|
||||
.monaco-editor .marker-widget .descriptioncontainer .filename {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
@@ -165,7 +165,7 @@ export abstract class ReferencesController implements IEditorContribution {
|
||||
let selection = this._model.nearestReference(uri, pos);
|
||||
if (selection) {
|
||||
return this._widget.setSelection(selection).then(() => {
|
||||
if (this._widget && this._editor.getOption(EditorOption.peekWidgetFocusInlineEditor)) {
|
||||
if (this._widget && this._editor.getOption(EditorOption.peekWidgetDefaultFocus) === 'editor') {
|
||||
this._widget.focusOnPreviewEditor();
|
||||
}
|
||||
});
|
||||
|
||||
@@ -110,3 +110,20 @@
|
||||
font-size: inherit;
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
.monaco-editor-hover .hover-contents a.code-link:before {
|
||||
content: '(';
|
||||
}
|
||||
.monaco-editor-hover .hover-contents a.code-link:after {
|
||||
content: ')';
|
||||
}
|
||||
|
||||
.monaco-editor-hover .hover-contents a.code-link {
|
||||
color: inherit;
|
||||
}
|
||||
.monaco-editor-hover .hover-contents a.code-link > span {
|
||||
text-decoration: underline;
|
||||
/** Hack to force underline to show **/
|
||||
border-bottom: 1px solid transparent;
|
||||
text-underline-position: under;
|
||||
}
|
||||
|
||||
@@ -22,7 +22,7 @@ import { getHover } from 'vs/editor/contrib/hover/getHover';
|
||||
import { HoverOperation, HoverStartMode, IHoverComputer } from 'vs/editor/contrib/hover/hoverOperation';
|
||||
import { ContentHoverWidget } from 'vs/editor/contrib/hover/hoverWidgets';
|
||||
import { MarkdownRenderer } from 'vs/editor/contrib/markdown/markdownRenderer';
|
||||
import { IThemeService } from 'vs/platform/theme/common/themeService';
|
||||
import { IThemeService, registerThemingParticipant } from 'vs/platform/theme/common/themeService';
|
||||
import { coalesce, isNonEmptyArray, asArray } from 'vs/base/common/arrays';
|
||||
import { IMarker, IMarkerData, MarkerSeverity } from 'vs/platform/markers/common/markers';
|
||||
import { basename } from 'vs/base/common/resources';
|
||||
@@ -39,6 +39,7 @@ import { IModeService } from 'vs/editor/common/services/modeService';
|
||||
import { IIdentifiedSingleEditOperation } from 'vs/editor/common/model';
|
||||
import { EditorOption } from 'vs/editor/common/config/editorOptions';
|
||||
import { Constants } from 'vs/base/common/uint';
|
||||
import { textLinkForeground } from 'vs/platform/theme/common/colorRegistry';
|
||||
|
||||
const $ = dom.$;
|
||||
|
||||
@@ -204,6 +205,8 @@ export class ModesContentHoverWidget extends ContentHoverWidget {
|
||||
private _shouldFocus: boolean;
|
||||
private _colorPicker: ColorPickerWidget | null;
|
||||
|
||||
private _codeLink?: HTMLElement;
|
||||
|
||||
private readonly renderDisposable = this._register(new MutableDisposable<IDisposable>());
|
||||
|
||||
constructor(
|
||||
@@ -500,10 +503,35 @@ export class ModesContentHoverWidget extends ContentHoverWidget {
|
||||
messageElement.innerText = message;
|
||||
|
||||
if (source || code) {
|
||||
const detailsElement = dom.append(markerElement, $('span'));
|
||||
detailsElement.style.opacity = '0.6';
|
||||
detailsElement.style.paddingLeft = '6px';
|
||||
detailsElement.innerText = source && code ? `${source}(${code})` : source ? source : `(${code})`;
|
||||
if (typeof code === 'string') {
|
||||
const detailsElement = dom.append(markerElement, $('span'));
|
||||
detailsElement.style.opacity = '0.6';
|
||||
detailsElement.style.paddingLeft = '6px';
|
||||
detailsElement.innerText = source && code ? `${source}(${code})` : source ? source : `(${code})`;
|
||||
} else {
|
||||
if (code) {
|
||||
const sourceAndCodeElement = $('span');
|
||||
if (source) {
|
||||
const sourceElement = dom.append(sourceAndCodeElement, $('span'));
|
||||
sourceElement.innerText = source;
|
||||
}
|
||||
this._codeLink = dom.append(sourceAndCodeElement, $('a.code-link'));
|
||||
this._codeLink.setAttribute('href', code.link.toString());
|
||||
|
||||
this._codeLink.onclick = (e) => {
|
||||
this._openerService.open(code.link);
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
};
|
||||
|
||||
const codeElement = dom.append(this._codeLink, $('span'));
|
||||
codeElement.innerText = code.value;
|
||||
|
||||
const detailsElement = dom.append(markerElement, sourceAndCodeElement);
|
||||
detailsElement.style.opacity = '0.6';
|
||||
detailsElement.style.paddingLeft = '6px';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (isNonEmptyArray(relatedInformation)) {
|
||||
@@ -648,3 +676,11 @@ function hoverContentsEquals(first: HoverPart[], second: HoverPart[]): boolean {
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
registerThemingParticipant((theme, collector) => {
|
||||
const linkFg = theme.getColor(textLinkForeground);
|
||||
if (linkFg) {
|
||||
collector.addRule(`.monaco-editor-hover .hover-contents a.code-link span:hover { color: ${linkFg}; }`);
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
@@ -451,7 +451,7 @@ export class AutoIndentOnPaste implements IEditorContribution {
|
||||
return;
|
||||
}
|
||||
|
||||
this.callOnModel.add(this.editor.onDidPaste((range: Range) => {
|
||||
this.callOnModel.add(this.editor.onDidPaste(({ range }) => {
|
||||
this.trigger(range);
|
||||
}));
|
||||
}
|
||||
|
||||
@@ -260,7 +260,7 @@ export abstract class PeekViewWidget extends ZoneWidget {
|
||||
|
||||
export const peekViewTitleBackground = registerColor('peekViewTitle.background', { dark: '#1E1E1E', light: '#FFFFFF', hc: '#0C141F' }, nls.localize('peekViewTitleBackground', 'Background color of the peek view title area.'));
|
||||
export const peekViewTitleForeground = registerColor('peekViewTitleLabel.foreground', { dark: '#FFFFFF', light: '#333333', hc: '#FFFFFF' }, nls.localize('peekViewTitleForeground', 'Color of the peek view title.'));
|
||||
export const peekViewTitleInfoForeground = registerColor('peekViewTitleDescription.foreground', { dark: '#ccccccb3', light: '#6c6c6cb3', hc: '#FFFFFF99' }, nls.localize('peekViewTitleInfoForeground', 'Color of the peek view title info.'));
|
||||
export const peekViewTitleInfoForeground = registerColor('peekViewTitleDescription.foreground', { dark: '#ccccccb3', light: '#616161e6', hc: '#FFFFFF99' }, nls.localize('peekViewTitleInfoForeground', 'Color of the peek view title info.'));
|
||||
export const peekViewBorder = registerColor('peekView.border', { dark: '#007acc', light: '#007acc', hc: contrastBorder }, nls.localize('peekViewBorder', 'Color of the peek view borders and arrow.'));
|
||||
|
||||
export const peekViewResultsBackground = registerColor('peekViewResult.background', { dark: '#252526', light: '#F3F3F3', hc: Color.black }, nls.localize('peekViewResultsBackground', 'Background color of the peek view result list.'));
|
||||
|
||||
@@ -341,8 +341,8 @@ Registry.as<IConfigurationRegistry>(Extensions.Configuration).registerConfigurat
|
||||
id: 'editor',
|
||||
properties: {
|
||||
'editor.rename.enablePreview': {
|
||||
scope: ConfigurationScope.RESOURCE_LANGUAGE,
|
||||
description: nls.localize('enablePreview', "Enabe/disable the ability to preview changes before renaming"),
|
||||
scope: ConfigurationScope.LANGUAGE_OVERRIDABLE,
|
||||
description: nls.localize('enablePreview', "Enable/disable the ability to preview changes before renaming"),
|
||||
default: true,
|
||||
type: 'boolean'
|
||||
}
|
||||
|
||||
@@ -9,12 +9,12 @@
|
||||
}
|
||||
|
||||
.monaco-editor .rename-box.preview {
|
||||
padding: 4px;
|
||||
padding: 3px 3px 0 3px;
|
||||
}
|
||||
|
||||
.monaco-editor .rename-box .rename-input {
|
||||
padding: 4px;
|
||||
width: calc(100% - 8px);
|
||||
padding: 3px;
|
||||
width: calc(100% - 6px);
|
||||
}
|
||||
|
||||
.monaco-editor .rename-box .rename-label {
|
||||
|
||||
@@ -192,6 +192,7 @@ export class CompletionModel {
|
||||
}
|
||||
}
|
||||
|
||||
const textLabel = typeof item.completion.label === 'string' ? item.completion.label : item.completion.label.name;
|
||||
if (wordPos >= wordLen) {
|
||||
// the wordPos at which scoring starts is the whole word
|
||||
// and therefore the same rules as not having a word apply
|
||||
@@ -206,19 +207,19 @@ export class CompletionModel {
|
||||
if (!match) {
|
||||
continue; // NO match
|
||||
}
|
||||
if (compareIgnoreCase(item.completion.filterText, item.completion.label) === 0) {
|
||||
if (compareIgnoreCase(item.completion.filterText, textLabel) === 0) {
|
||||
// filterText and label are actually the same -> use good highlights
|
||||
item.score = match;
|
||||
} else {
|
||||
// re-run the scorer on the label in the hope of a result BUT use the rank
|
||||
// of the filterText-match
|
||||
item.score = anyScore(word, wordLow, wordPos, item.completion.label, item.labelLow, 0);
|
||||
item.score = anyScore(word, wordLow, wordPos, textLabel, item.labelLow, 0);
|
||||
item.score[0] = match[0]; // use score from filterText
|
||||
}
|
||||
|
||||
} else {
|
||||
// by default match `word` against the `label`
|
||||
let match = scoreFn(word, wordLow, wordPos, item.completion.label, item.labelLow, 0, false);
|
||||
let match = scoreFn(word, wordLow, wordPos, textLabel, item.labelLow, 0, false);
|
||||
if (!match) {
|
||||
continue; // NO match
|
||||
}
|
||||
|
||||
@@ -99,20 +99,25 @@
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: pre;
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
.monaco-editor .suggest-widget .monaco-list .monaco-list-row > .contents > .main > .left,
|
||||
.monaco-editor .suggest-widget .monaco-list .monaco-list-row > .contents > .main > .right {
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.monaco-editor .suggest-widget:not(.frozen) .monaco-highlighted-label .highlight {
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
/** Icon styles **/
|
||||
/** ReadMore Icon styles **/
|
||||
|
||||
.monaco-editor .suggest-widget .details > .monaco-scrollable-element > .body > .header > .codicon-close,
|
||||
.monaco-editor .suggest-widget .monaco-list .monaco-list-row > .contents > .main > .readMore::before {
|
||||
.monaco-editor .suggest-widget .monaco-list .monaco-list-row > .contents > .main > .right > .readMore::before {
|
||||
color: inherit;
|
||||
opacity: 0.6;
|
||||
opacity: 1;
|
||||
font-size: 14px;
|
||||
margin-left: 4px;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
@@ -123,39 +128,110 @@
|
||||
}
|
||||
|
||||
.monaco-editor .suggest-widget .details > .monaco-scrollable-element > .body > .header > .codicon-close:hover,
|
||||
.monaco-editor .suggest-widget .monaco-list .monaco-list-row > .contents > .main > .readMore:hover {
|
||||
.monaco-editor .suggest-widget .monaco-list .monaco-list-row > .contents > .main > .right > .readMore:hover {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
/** signature, qualifier, type/details opacity **/
|
||||
.monaco-editor .suggest-widget .monaco-list .monaco-list-row > .contents > .main > .left > .signature-label,
|
||||
.monaco-editor .suggest-widget .monaco-list .monaco-list-row > .contents > .main > .left > .qualifier-label,
|
||||
.monaco-editor .suggest-widget .monaco-list .monaco-list-row > .contents > .main > .right > .details-label {
|
||||
opacity: 0.7;
|
||||
}
|
||||
|
||||
.monaco-editor .suggest-widget .monaco-list .monaco-list-row > .contents > .main > .left > .qualifier-label {
|
||||
margin-left: 4px;
|
||||
opacity: 0.4;
|
||||
font-size: 90%;
|
||||
text-overflow: ellipsis;
|
||||
overflow: hidden;
|
||||
line-height: 17px;
|
||||
align-self: center;
|
||||
}
|
||||
|
||||
/** Type Info and icon next to the label in the focused completion item **/
|
||||
|
||||
.monaco-editor .suggest-widget .monaco-list .monaco-list-row > .contents > .main > .type-label {
|
||||
.monaco-editor .suggest-widget .monaco-list .monaco-list-row > .contents > .main > .right > .details-label {
|
||||
margin-left: 0.8em;
|
||||
flex: 1;
|
||||
text-align: right;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
opacity: 0.7;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.monaco-editor .suggest-widget .monaco-list .monaco-list-row > .contents > .main > .type-label > .monaco-tokenized-source {
|
||||
.monaco-editor .suggest-widget .monaco-list .monaco-list-row > .contents > .main > .right > .details-label > .monaco-tokenized-source {
|
||||
display: inline;
|
||||
}
|
||||
|
||||
.monaco-editor .suggest-widget .monaco-list .monaco-list-row > .contents > .main > .readMore,
|
||||
.monaco-editor .suggest-widget .monaco-list .monaco-list-row > .contents > .main > .type-label,
|
||||
.monaco-editor .suggest-widget.docs-side .monaco-list .monaco-list-row.focused > .contents > .main > .readMore,
|
||||
.monaco-editor .suggest-widget.docs-side .monaco-list .monaco-list-row.focused > .contents > .main > .type-label,
|
||||
.monaco-editor .suggest-widget.docs-below .monaco-list .monaco-list-row.focused > .contents > .main > .readMore {
|
||||
/** Details: if using CompletionItem#details, show on focus **/
|
||||
|
||||
.monaco-editor .suggest-widget .monaco-list .monaco-list-row > .contents > .main > .right > .details-label,
|
||||
.monaco-editor .suggest-widget.docs-side .monaco-list .monaco-list-row.focused > .contents > .main > .right > .details-label {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.monaco-editor .suggest-widget .monaco-list .monaco-list-row.focused > .contents > .main > .readMore,
|
||||
.monaco-editor .suggest-widget .monaco-list .monaco-list-row.focused > .contents > .main > .type-label {
|
||||
.monaco-editor .suggest-widget .monaco-list .monaco-list-row.focused > .contents > .main > .right > .details-label {
|
||||
display: inline;
|
||||
}
|
||||
|
||||
/** Details: if using CompletionItemLabel#details, always show **/
|
||||
|
||||
.monaco-editor .suggest-widget .monaco-list .monaco-list-row > .contents > .main > .right.always-show-details > .details-label,
|
||||
.monaco-editor .suggest-widget.docs-side .monaco-list .monaco-list-row.focused > .contents > .main > .right.always-show-details > .details-label {
|
||||
display: inline;
|
||||
}
|
||||
|
||||
/** Ellipsis on hover **/
|
||||
.monaco-editor .suggest-widget:not(.docs-side) .monaco-list .monaco-list-row:hover > .contents > .main > .right.can-expand-details > .details-label {
|
||||
width: calc(100% - 26px);
|
||||
}
|
||||
|
||||
.monaco-editor .suggest-widget .monaco-list .monaco-list-row > .contents > .main > .left {
|
||||
flex-shrink: 1;
|
||||
overflow: hidden;
|
||||
}
|
||||
.monaco-editor .suggest-widget .monaco-list .monaco-list-row > .contents > .main > .left > .monaco-icon-label {
|
||||
flex-shrink: 0;
|
||||
}
|
||||
.monaco-editor .suggest-widget .monaco-list .monaco-list-row > .contents > .main > .right {
|
||||
overflow: hidden;
|
||||
margin-left: 16px;
|
||||
flex-shrink: 0;
|
||||
max-width: 45%;
|
||||
}
|
||||
|
||||
.monaco-editor .suggest-widget .monaco-list .monaco-list-row > .contents > .main > .right > .readMore {
|
||||
display: inline-block;
|
||||
position: absolute;
|
||||
right: 10px;
|
||||
width: 18px;
|
||||
height: 18px;
|
||||
visibility: hidden;
|
||||
}
|
||||
|
||||
/** Do NOT display ReadMore when docs is side/below **/
|
||||
.monaco-editor .suggest-widget.docs-side .monaco-list .monaco-list-row > .contents > .main > .right > .readMore,
|
||||
.monaco-editor .suggest-widget.docs-below .monaco-list .monaco-list-row > .contents > .main > .right > .readMore {
|
||||
display: none !important;
|
||||
}
|
||||
|
||||
/** Do NOT display ReadMore when using plain CompletionItemLabel (details/documentation might not be resolved) **/
|
||||
.monaco-editor .suggest-widget .monaco-list .monaco-list-row > .contents > .main > .right:not(.always-show-details) > .readMore {
|
||||
display: none;
|
||||
}
|
||||
/** Focused item can show ReadMore, but can't when docs is side/below **/
|
||||
.monaco-editor .suggest-widget .monaco-list .monaco-list-row.focused > .contents > .main > .right:not(.always-show-details) > .readMore {
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.monaco-editor .suggest-widget.docs-side .monaco-list .monaco-list-row > .contents > .main > .right > .readMore,
|
||||
.monaco-editor .suggest-widget.docs-below .monaco-list .monaco-list-row > .contents > .main > .right > .readMore {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.monaco-editor .suggest-widget .monaco-list .monaco-list-row:hover > .contents > .main > .right > .readMore {
|
||||
visibility: visible;
|
||||
}
|
||||
|
||||
/** Styles for each row in the list **/
|
||||
|
||||
.monaco-editor .suggest-widget .monaco-list .monaco-list-row .monaco-icon-label.deprecated {
|
||||
|
||||
@@ -37,6 +37,9 @@ export class CompletionItem {
|
||||
readonly editInsertEnd: IPosition;
|
||||
readonly editReplaceEnd: IPosition;
|
||||
|
||||
//
|
||||
readonly textLabel: string;
|
||||
|
||||
// perf
|
||||
readonly labelLow: string;
|
||||
readonly sortTextLow?: string;
|
||||
@@ -48,9 +51,6 @@ export class CompletionItem {
|
||||
idx?: number;
|
||||
word?: string;
|
||||
|
||||
//
|
||||
readonly isDetailsResolved: boolean;
|
||||
|
||||
constructor(
|
||||
readonly position: IPosition,
|
||||
readonly completion: modes.CompletionItem,
|
||||
@@ -58,8 +58,13 @@ export class CompletionItem {
|
||||
readonly provider: modes.CompletionItemProvider,
|
||||
model: ITextModel
|
||||
) {
|
||||
this.textLabel = typeof completion.label === 'string'
|
||||
? completion.label
|
||||
: completion.label.name;
|
||||
|
||||
// ensure lower-variants (perf)
|
||||
this.labelLow = completion.label.toLowerCase();
|
||||
this.labelLow = this.textLabel.toLowerCase();
|
||||
|
||||
this.sortTextLow = completion.sortText && completion.sortText.toLowerCase();
|
||||
this.filterTextLow = completion.filterText && completion.filterText.toLowerCase();
|
||||
|
||||
@@ -74,8 +79,6 @@ export class CompletionItem {
|
||||
this.editReplaceEnd = new Position(completion.range.replace.endLineNumber, completion.range.replace.endColumn);
|
||||
}
|
||||
|
||||
this.isDetailsResolved = container.isDetailsResolved || typeof provider.resolveCompletionItem === 'undefined';
|
||||
|
||||
// create the suggestion resolver
|
||||
const { resolveCompletionItem } = provider;
|
||||
if (typeof resolveCompletionItem !== 'function') {
|
||||
@@ -189,7 +192,7 @@ export function provideSuggestionItems(
|
||||
}
|
||||
// fill in default sortText when missing
|
||||
if (!suggestion.sortText) {
|
||||
suggestion.sortText = suggestion.label;
|
||||
suggestion.sortText = typeof suggestion.label === 'string' ? suggestion.label : suggestion.label.name;
|
||||
}
|
||||
|
||||
allSuggestions.push(new CompletionItem(position, suggestion, container, provider, model));
|
||||
|
||||
@@ -341,8 +341,9 @@ export class SuggestController implements IEditorContribution {
|
||||
}
|
||||
|
||||
private _alertCompletionItem({ completion: suggestion }: CompletionItem): void {
|
||||
const textLabel = typeof suggestion.label === 'string' ? suggestion.label : suggestion.label.name;
|
||||
if (isNonEmptyArray(suggestion.additionalTextEdits)) {
|
||||
let msg = nls.localize('arai.alert.snippet', "Accepting '{0}' made {1} additional edits", suggestion.label, suggestion.additionalTextEdits.length);
|
||||
let msg = nls.localize('arai.alert.snippet', "Accepting '{0}' made {1} additional edits", textLabel, suggestion.additionalTextEdits.length);
|
||||
alert(msg);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -142,10 +142,10 @@ export class SuggestModel implements IDisposable {
|
||||
}));
|
||||
|
||||
let editorIsComposing = false;
|
||||
this._toDispose.add(this._editor.onCompositionStart(() => {
|
||||
this._toDispose.add(this._editor.onDidCompositionStart(() => {
|
||||
editorIsComposing = true;
|
||||
}));
|
||||
this._toDispose.add(this._editor.onCompositionEnd(() => {
|
||||
this._toDispose.add(this._editor.onDidCompositionEnd(() => {
|
||||
// refilter when composition ends
|
||||
editorIsComposing = false;
|
||||
this._refilterCompletionItems();
|
||||
@@ -233,7 +233,7 @@ export class SuggestModel implements IDisposable {
|
||||
};
|
||||
|
||||
this._triggerCharacterListener.add(this._editor.onDidType(checkTriggerCharacter));
|
||||
this._triggerCharacterListener.add(this._editor.onCompositionEnd(checkTriggerCharacter));
|
||||
this._triggerCharacterListener.add(this._editor.onDidCompositionEnd(checkTriggerCharacter));
|
||||
}
|
||||
|
||||
// --- trigger/retrigger/cancel suggest
|
||||
@@ -286,9 +286,7 @@ export class SuggestModel implements IDisposable {
|
||||
) {
|
||||
// Early exit if nothing needs to be done!
|
||||
// Leave some form of early exit check here if you wish to continue being a cursor position change listener ;)
|
||||
if (this._state !== State.Idle) {
|
||||
this.cancel();
|
||||
}
|
||||
this.cancel();
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@@ -46,11 +46,25 @@ const expandSuggestionDocsByDefault = false;
|
||||
|
||||
interface ISuggestionTemplateData {
|
||||
root: HTMLElement;
|
||||
|
||||
/**
|
||||
* Flexbox
|
||||
* < ------- left ------- > < -------- right -------- >
|
||||
* <icon><label><signature> <qualifier><type><readmore>
|
||||
*/
|
||||
left: HTMLElement;
|
||||
right: HTMLElement;
|
||||
|
||||
icon: HTMLElement;
|
||||
colorspan: HTMLElement;
|
||||
iconLabel: IconLabel;
|
||||
iconContainer: HTMLElement;
|
||||
typeLabel: HTMLElement;
|
||||
signatureLabel: HTMLElement;
|
||||
qualifierLabel: HTMLElement;
|
||||
/**
|
||||
* Showing either `CompletionItem#details` or `CompletionItemLabel#type`
|
||||
*/
|
||||
detailsLabel: HTMLElement;
|
||||
readMore: HTMLElement;
|
||||
disposables: DisposableStore;
|
||||
}
|
||||
@@ -66,8 +80,12 @@ export const editorSuggestWidgetHighlightForeground = registerColor('editorSugge
|
||||
|
||||
const colorRegExp = /^(#([\da-f]{3}){1,2}|(rgb|hsl)a\(\s*(\d{1,3}%?\s*,\s*){3}(1|0?\.\d+)\)|(rgb|hsl)\(\s*\d{1,3}%?(\s*,\s*\d{1,3}%?){2}\s*\))$/i;
|
||||
function extractColor(item: CompletionItem, out: string[]): boolean {
|
||||
if (item.completion.label.match(colorRegExp)) {
|
||||
out[0] = item.completion.label;
|
||||
const label = typeof item.completion.label === 'string'
|
||||
? item.completion.label
|
||||
: item.completion.label.name;
|
||||
|
||||
if (label.match(colorRegExp)) {
|
||||
out[0] = label;
|
||||
return true;
|
||||
}
|
||||
if (typeof item.completion.documentation === 'string' && item.completion.documentation.match(colorRegExp)) {
|
||||
@@ -92,7 +110,7 @@ function getAriaId(index: number): string {
|
||||
return `suggest-aria-id:${index}`;
|
||||
}
|
||||
|
||||
class Renderer implements IListRenderer<CompletionItem, ISuggestionTemplateData> {
|
||||
class ItemRenderer implements IListRenderer<CompletionItem, ISuggestionTemplateData> {
|
||||
|
||||
constructor(
|
||||
private widget: SuggestWidget,
|
||||
@@ -122,14 +140,19 @@ class Renderer implements IListRenderer<CompletionItem, ISuggestionTemplateData>
|
||||
const text = append(container, $('.contents'));
|
||||
const main = append(text, $('.main'));
|
||||
|
||||
data.iconContainer = append(main, $('.icon-label.codicon'));
|
||||
data.left = append(main, $('span.left'));
|
||||
data.right = append(main, $('span.right'));
|
||||
|
||||
data.iconLabel = new IconLabel(main, { supportHighlights: true, supportCodicons: true });
|
||||
data.iconContainer = append(data.left, $('.icon-label.codicon'));
|
||||
|
||||
data.iconLabel = new IconLabel(data.left, { supportHighlights: true, supportCodicons: true });
|
||||
data.disposables.add(data.iconLabel);
|
||||
|
||||
data.typeLabel = append(main, $('span.type-label'));
|
||||
data.signatureLabel = append(data.left, $('span.signature-label'));
|
||||
data.qualifierLabel = append(data.left, $('span.qualifier-label'));
|
||||
data.detailsLabel = append(data.right, $('span.details-label'));
|
||||
|
||||
data.readMore = append(main, $('span.readMore.codicon.codicon-info'));
|
||||
data.readMore = append(data.right, $('span.readMore.codicon.codicon-info'));
|
||||
data.readMore.title = nls.localize('readMore', "Read More...{0}", this.triggerKeybindingLabel);
|
||||
|
||||
const configureFont = () => {
|
||||
@@ -166,6 +189,7 @@ class Renderer implements IListRenderer<CompletionItem, ISuggestionTemplateData>
|
||||
renderElement(element: CompletionItem, index: number, templateData: ISuggestionTemplateData): void {
|
||||
const data = <ISuggestionTemplateData>templateData;
|
||||
const suggestion = (<CompletionItem>element).completion;
|
||||
const textLabel = typeof suggestion.label === 'string' ? suggestion.label : suggestion.label.name;
|
||||
|
||||
data.root.id = getAriaId(index);
|
||||
data.icon.className = 'icon ' + completionKindToCssClass(suggestion.kind);
|
||||
@@ -187,7 +211,7 @@ class Renderer implements IListRenderer<CompletionItem, ISuggestionTemplateData>
|
||||
// special logic for 'file' completion items
|
||||
data.icon.className = 'icon hide';
|
||||
data.iconContainer.className = 'icon hide';
|
||||
const labelClasses = getIconClasses(this._modelService, this._modeService, URI.from({ scheme: 'fake', path: suggestion.label }), FileKind.FILE);
|
||||
const labelClasses = getIconClasses(this._modelService, this._modeService, URI.from({ scheme: 'fake', path: textLabel }), FileKind.FILE);
|
||||
const detailClasses = getIconClasses(this._modelService, this._modeService, URI.from({ scheme: 'fake', path: suggestion.detail }), FileKind.FILE);
|
||||
labelOptions.extraClasses = labelClasses.length > detailClasses.length ? labelClasses : detailClasses;
|
||||
|
||||
@@ -196,7 +220,7 @@ class Renderer implements IListRenderer<CompletionItem, ISuggestionTemplateData>
|
||||
data.icon.className = 'icon hide';
|
||||
data.iconContainer.className = 'icon hide';
|
||||
labelOptions.extraClasses = flatten([
|
||||
getIconClasses(this._modelService, this._modeService, URI.from({ scheme: 'fake', path: suggestion.label }), FileKind.FOLDER),
|
||||
getIconClasses(this._modelService, this._modeService, URI.from({ scheme: 'fake', path: textLabel }), FileKind.FOLDER),
|
||||
getIconClasses(this._modelService, this._modeService, URI.from({ scheme: 'fake', path: suggestion.detail }), FileKind.FOLDER)
|
||||
]);
|
||||
} else {
|
||||
@@ -211,10 +235,21 @@ class Renderer implements IListRenderer<CompletionItem, ISuggestionTemplateData>
|
||||
labelOptions.matches = [];
|
||||
}
|
||||
|
||||
data.iconLabel.setLabel(suggestion.label, undefined, labelOptions);
|
||||
data.typeLabel.textContent = (suggestion.detail || '').replace(/\n.*$/m, '');
|
||||
data.iconLabel.setLabel(textLabel, undefined, labelOptions);
|
||||
if (typeof suggestion.label === 'string') {
|
||||
data.signatureLabel.textContent = '';
|
||||
data.qualifierLabel.textContent = '';
|
||||
data.detailsLabel.textContent = (suggestion.detail || '').replace(/\n.*$/m, '');
|
||||
removeClass(data.right, 'always-show-details');
|
||||
} else {
|
||||
data.signatureLabel.textContent = (suggestion.label.signature || '').replace(/\n.*$/m, '');
|
||||
data.qualifierLabel.textContent = (suggestion.label.qualifier || '').replace(/\n.*$/m, '');
|
||||
data.detailsLabel.textContent = (suggestion.label.type || '').replace(/\n.*$/m, '');
|
||||
addClass(data.right, 'always-show-details');
|
||||
}
|
||||
|
||||
if (canExpandCompletionItem(element)) {
|
||||
addClass(data.right, 'can-expand-details');
|
||||
show(data.readMore);
|
||||
data.readMore.onmousedown = e => {
|
||||
e.stopPropagation();
|
||||
@@ -226,6 +261,7 @@ class Renderer implements IListRenderer<CompletionItem, ISuggestionTemplateData>
|
||||
this.widget.toggleDetails();
|
||||
};
|
||||
} else {
|
||||
removeClass(data.right, 'can-expand-details');
|
||||
hide(data.readMore);
|
||||
data.readMore.onmousedown = null;
|
||||
data.readMore.onclick = null;
|
||||
@@ -511,7 +547,7 @@ export class SuggestWidget implements IContentWidget, IListVirtualDelegate<Compl
|
||||
const applyIconStyle = () => toggleClass(this.element, 'no-icons', !this.editor.getOption(EditorOption.suggest).showIcons);
|
||||
applyIconStyle();
|
||||
|
||||
let renderer = instantiationService.createInstance(Renderer, this, this.editor, triggerKeybindingLabel);
|
||||
let renderer = instantiationService.createInstance(ItemRenderer, this, this.editor, triggerKeybindingLabel);
|
||||
|
||||
this.list = new List('SuggestWidget', this.listElement, this, [renderer], {
|
||||
useShadows: false,
|
||||
@@ -519,6 +555,7 @@ export class SuggestWidget implements IContentWidget, IListVirtualDelegate<Compl
|
||||
mouseSupport: false,
|
||||
accessibilityProvider: {
|
||||
getAriaLabel: (item: CompletionItem) => {
|
||||
const textLabel = typeof item.completion.label === 'string' ? item.completion.label : item.completion.label.name;
|
||||
if (item.isResolved && this.expandDocsSettingFromStorage()) {
|
||||
const { documentation, detail } = item.completion;
|
||||
const docs = strings.format(
|
||||
@@ -526,9 +563,9 @@ export class SuggestWidget implements IContentWidget, IListVirtualDelegate<Compl
|
||||
detail || '',
|
||||
documentation ? (typeof documentation === 'string' ? documentation : documentation.value) : '');
|
||||
|
||||
return nls.localize('ariaCurrenttSuggestionReadDetails', "Item {0}, docs: {1}", item.completion.label, docs);
|
||||
return nls.localize('ariaCurrenttSuggestionReadDetails', "Item {0}, docs: {1}", textLabel, docs);
|
||||
} else {
|
||||
return item.completion.label;
|
||||
return textLabel;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -545,7 +582,7 @@ export class SuggestWidget implements IContentWidget, IListVirtualDelegate<Compl
|
||||
this.toDispose.add(this.list.onSelectionChange(e => this.onListSelection(e)));
|
||||
this.toDispose.add(this.list.onFocusChange(e => this.onListFocus(e)));
|
||||
this.toDispose.add(this.editor.onDidChangeCursorSelection(() => this.onCursorSelectionChanged()));
|
||||
this.toDispose.add(this.editor.onDidChangeConfiguration(e => e.hasChanged(EditorOption.suggest) && applyIconStyle()));
|
||||
this.toDispose.add(this.editor.onDidChangeConfiguration(e => { if (e.hasChanged(EditorOption.suggest)) { applyIconStyle(); } }));
|
||||
|
||||
this.suggestWidgetVisible = SuggestContext.Visible.bindTo(contextKeyService);
|
||||
this.suggestWidgetMultipleSuggestions = SuggestContext.MultipleSuggestions.bindTo(contextKeyService);
|
||||
|
||||
@@ -48,7 +48,7 @@ export abstract class WordDistance {
|
||||
if (suggestion.kind === CompletionItemKind.Keyword) {
|
||||
return 2 << 20;
|
||||
}
|
||||
let word = suggestion.label;
|
||||
let word = typeof suggestion.label === 'string' ? suggestion.label : suggestion.label.name;
|
||||
let wordLines = wordRanges[word];
|
||||
if (isFalsyOrEmpty(wordLines)) {
|
||||
return 2 << 20;
|
||||
|
||||
Reference in New Issue
Block a user