Merge from vscode 2cd495805cf99b31b6926f08ff4348124b2cf73d

This commit is contained in:
ADS Merger
2020-06-30 04:40:21 +00:00
committed by AzureDataStudio
parent a8a7559229
commit 1388493cc1
602 changed files with 16375 additions and 12940 deletions

View File

@@ -7,7 +7,7 @@ import * as nls from 'vs/nls';
import { KeyCode, KeyMod } from 'vs/base/common/keyCodes';
import * as types from 'vs/base/common/types';
import { ICodeEditor } from 'vs/editor/browser/editorBrowser';
import { Command, EditorCommand, ICommandOptions, registerEditorCommand } from 'vs/editor/browser/editorExtensions';
import { Command, EditorCommand, ICommandOptions, registerEditorCommand, MultiCommand, UndoCommand, RedoCommand, SelectAllCommand } from 'vs/editor/browser/editorExtensions';
import { ICodeEditorService } from 'vs/editor/browser/services/codeEditorService';
import { ColumnSelection, IColumnSelectResult } from 'vs/editor/common/controller/cursorColumnSelection';
import { CursorState, EditOperationType, IColumnSelectData, PartialCursorState } from 'vs/editor/common/controller/cursorCommon';
@@ -20,7 +20,6 @@ import { Range } from 'vs/editor/common/core/range';
import { Handler, ScrollType } from 'vs/editor/common/editorCommon';
import { EditorContextKeys } from 'vs/editor/common/editorContextKeys';
import { VerticalRevealType } from 'vs/editor/common/view/viewEvents';
import { MenuId } from 'vs/platform/actions/common/actions';
import { ICommandHandlerDescription } from 'vs/platform/commands/common/commands';
import { ContextKeyExpr } from 'vs/platform/contextkey/common/contextkey';
import { ServicesAccessor } from 'vs/platform/instantiation/common/instantiation';
@@ -276,6 +275,48 @@ export namespace RevealLine_ {
};
}
abstract class EditorOrNativeTextInputCommand {
constructor(target: MultiCommand) {
// 1. handle case when focus is in editor.
target.addImplementation(10000, (accessor: ServicesAccessor, args: any) => {
// Only if editor text focus (i.e. not if editor has widget focus).
const focusedEditor = accessor.get(ICodeEditorService).getFocusedCodeEditor();
if (focusedEditor && focusedEditor.hasTextFocus()) {
this.runEditorCommand(accessor, focusedEditor, args);
return true;
}
return false;
});
// 2. handle case when focus is in some other `input` / `textarea`.
target.addImplementation(1000, (accessor: ServicesAccessor, args: any) => {
// Only if focused on an element that allows for entering text
const activeElement = <HTMLElement>document.activeElement;
if (activeElement && ['input', 'textarea'].indexOf(activeElement.tagName.toLowerCase()) >= 0) {
this.runDOMCommand();
return true;
}
return false;
});
// 3. (default) handle case when focus is somewhere else.
target.addImplementation(0, (accessor: ServicesAccessor, args: any) => {
// Redirecting to active editor
const activeEditor = accessor.get(ICodeEditorService).getActiveCodeEditor();
if (activeEditor) {
activeEditor.focus();
this.runEditorCommand(accessor, activeEditor, args);
return true;
}
return false;
});
}
public abstract runDOMCommand(): void;
public abstract runEditorCommand(accessor: ServicesAccessor | null, editor: ICodeEditor, args: any): void;
}
export namespace CoreNavigationCommands {
class BaseMoveToCommand extends CoreEditorCommand {
@@ -1594,25 +1635,32 @@ export namespace CoreNavigationCommands {
}
});
export const SelectAll: CoreEditorCommand = registerEditorCommand(new class extends CoreEditorCommand {
export const SelectAll = new class extends EditorOrNativeTextInputCommand {
constructor() {
super({
id: 'selectAll',
precondition: undefined
});
super(SelectAllCommand);
}
public runDOMCommand(): void {
document.execCommand('selectAll');
}
public runEditorCommand(accessor: ServicesAccessor, editor: ICodeEditor, args: any): void {
const viewModel = editor._getViewModel();
if (!viewModel) {
// the editor has no view => has no cursors
return;
}
this.runCoreEditorCommand(viewModel, args);
}
public runCoreEditorCommand(viewModel: IViewModel, args: any): void {
viewModel.model.pushStackElement();
viewModel.setCursorStates(
args.source,
'keyboard',
CursorChangeReason.Explicit,
[
CursorMoveCommands.selectAll(viewModel, viewModel.getPrimaryCursorState())
]
);
}
});
}();
export const SetSelection: CoreEditorCommand = registerEditorCommand(new class extends CoreEditorCommand {
constructor() {
@@ -1655,97 +1703,6 @@ registerColumnSelection(CoreNavigationCommands.CursorColumnSelectPageUp.id, KeyM
registerColumnSelection(CoreNavigationCommands.CursorColumnSelectDown.id, KeyMod.Shift | KeyCode.DownArrow);
registerColumnSelection(CoreNavigationCommands.CursorColumnSelectPageDown.id, KeyMod.Shift | KeyCode.PageDown);
/**
* A command that will:
* 1. invoke a command on the focused editor.
* 2. otherwise, invoke a browser built-in command on the `activeElement`.
* 3. otherwise, invoke a command on the workbench active editor.
*/
abstract class EditorOrNativeTextInputCommand extends Command {
public runCommand(accessor: ServicesAccessor, args: any): void {
const focusedEditor = accessor.get(ICodeEditorService).getFocusedCodeEditor();
// Only if editor text focus (i.e. not if editor has widget focus).
if (focusedEditor && focusedEditor.hasTextFocus()) {
return this.runEditorCommand(accessor, focusedEditor, args);
}
// Ignore this action when user is focused on an element that allows for entering text
const activeElement = <HTMLElement>document.activeElement;
if (activeElement && ['input', 'textarea'].indexOf(activeElement.tagName.toLowerCase()) >= 0) {
return this.runDOMCommand();
}
// Redirecting to active editor
const activeEditor = accessor.get(ICodeEditorService).getActiveCodeEditor();
if (activeEditor) {
activeEditor.focus();
return this.runEditorCommand(accessor, activeEditor, args);
}
}
public abstract runDOMCommand(): void;
public abstract runEditorCommand(accessor: ServicesAccessor, editor: ICodeEditor, args: any): void;
}
class SelectAllCommand extends EditorOrNativeTextInputCommand {
constructor() {
super({
id: 'editor.action.selectAll',
precondition: EditorContextKeys.textInputFocus,
kbOpts: {
weight: CORE_WEIGHT,
kbExpr: null,
primary: KeyMod.CtrlCmd | KeyCode.KEY_A
},
menuOpts: [{
menuId: MenuId.MenubarEditMenu, // {{SQL CARBON EDIT}} - Put this in the edit menu since we disabled the selection menu
group: '4_find_global', // {{SQL CARBON EDIT}} - Put this in the edit menu since we disabled the selection menu
title: nls.localize({ key: 'miSelectAll', comment: ['&& denotes a mnemonic'] }, "&&Select All"),
order: 1
}, {
menuId: MenuId.CommandPalette,
group: '',
title: nls.localize('selectAll', "Select All"),
order: 1
}]
});
}
public runDOMCommand(): void {
document.execCommand('selectAll');
}
public runEditorCommand(accessor: ServicesAccessor, editor: ICodeEditor, args: any): void {
args = args || {};
args.source = 'keyboard';
CoreNavigationCommands.SelectAll.runEditorCommand(accessor, editor, args);
}
}
class UndoCommand extends EditorOrNativeTextInputCommand {
public runDOMCommand(): void {
document.execCommand('undo');
}
public runEditorCommand(accessor: ServicesAccessor | null, editor: ICodeEditor, args: any): void {
if (!editor.hasModel() || editor.getOption(EditorOption.readOnly) === true) {
return;
}
editor.getModel().undo();
}
}
class RedoCommand extends EditorOrNativeTextInputCommand {
public runDOMCommand(): void {
document.execCommand('redo');
}
public runEditorCommand(accessor: ServicesAccessor | null, editor: ICodeEditor, args: any): void {
if (!editor.hasModel() || editor.getOption(EditorOption.readOnly) === true) {
return;
}
editor.getModel().redo();
}
}
function registerCommand<T extends Command>(command: T): T {
command.register();
return command;
@@ -1881,53 +1838,35 @@ export namespace CoreEditingCommands {
}
});
export const Undo: UndoCommand = registerCommand(new UndoCommand({
id: 'undo',
precondition: EditorContextKeys.writable,
kbOpts: {
weight: CORE_WEIGHT,
kbExpr: EditorContextKeys.textInputFocus,
primary: KeyMod.CtrlCmd | KeyCode.KEY_Z
},
menuOpts: [{
menuId: MenuId.MenubarEditMenu,
group: '1_do',
title: nls.localize({ key: 'miUndo', comment: ['&& denotes a mnemonic'] }, "&&Undo"),
order: 1
}, {
menuId: MenuId.CommandPalette,
group: '',
title: nls.localize('undo', "Undo"),
order: 1
}]
}));
export const Undo = new class extends EditorOrNativeTextInputCommand {
constructor() {
super(UndoCommand);
}
public runDOMCommand(): void {
document.execCommand('undo');
}
public runEditorCommand(accessor: ServicesAccessor | null, editor: ICodeEditor, args: any): void {
if (!editor.hasModel() || editor.getOption(EditorOption.readOnly) === true) {
return;
}
editor.getModel().undo();
}
}();
export const DefaultUndo: UndoCommand = registerCommand(new UndoCommand({ id: 'default:undo', precondition: EditorContextKeys.writable }));
export const Redo: RedoCommand = registerCommand(new RedoCommand({
id: 'redo',
precondition: EditorContextKeys.writable,
kbOpts: {
weight: CORE_WEIGHT,
kbExpr: EditorContextKeys.textInputFocus,
primary: KeyMod.CtrlCmd | KeyCode.KEY_Y,
secondary: [KeyMod.CtrlCmd | KeyMod.Shift | KeyCode.KEY_Z],
mac: { primary: KeyMod.CtrlCmd | KeyMod.Shift | KeyCode.KEY_Z }
},
menuOpts: [{
menuId: MenuId.MenubarEditMenu,
group: '1_do',
title: nls.localize({ key: 'miRedo', comment: ['&& denotes a mnemonic'] }, "&&Redo"),
order: 2
}, {
menuId: MenuId.CommandPalette,
group: '',
title: nls.localize('redo', "Redo"),
order: 1
}]
}));
export const DefaultRedo: RedoCommand = registerCommand(new RedoCommand({ id: 'default:redo', precondition: EditorContextKeys.writable }));
export const Redo = new class extends EditorOrNativeTextInputCommand {
constructor() {
super(RedoCommand);
}
public runDOMCommand(): void {
document.execCommand('redo');
}
public runEditorCommand(accessor: ServicesAccessor | null, editor: ICodeEditor, args: any): void {
if (!editor.hasModel() || editor.getOption(EditorOption.readOnly) === true) {
return;
}
editor.getModel().redo();
}
}();
}
/**
@@ -1956,8 +1895,6 @@ class EditorHandlerCommand extends Command {
}
}
registerCommand(new SelectAllCommand());
function registerOverwritableCommand(handlerId: string, description?: ICommandHandlerDescription): void {
registerCommand(new EditorHandlerCommand('default:' + handlerId, handlerId));
registerCommand(new EditorHandlerCommand(handlerId, handlerId, description));

View File

@@ -3,6 +3,7 @@
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import * as nls from 'vs/nls';
import { IPosition } from 'vs/base/browser/ui/contextview/contextview';
import { illegalArgument } from 'vs/base/common/errors';
import { URI } from 'vs/base/common/uri';
@@ -17,11 +18,13 @@ import { MenuId, MenuRegistry } from 'vs/platform/actions/common/actions';
import { CommandsRegistry, ICommandHandlerDescription } from 'vs/platform/commands/common/commands';
import { ContextKeyExpr, IContextKeyService, ContextKeyExpression } from 'vs/platform/contextkey/common/contextkey';
import { IConstructorSignature1, ServicesAccessor as InstantiationServicesAccessor, BrandedService } from 'vs/platform/instantiation/common/instantiation';
import { IKeybindings, KeybindingsRegistry } from 'vs/platform/keybinding/common/keybindingsRegistry';
import { IKeybindings, KeybindingsRegistry, KeybindingWeight } from 'vs/platform/keybinding/common/keybindingsRegistry';
import { Registry } from 'vs/platform/registry/common/platform';
import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
import { withNullAsUndefined, assertType } from 'vs/base/common/types';
import { ThemeIcon } from 'vs/platform/theme/common/themeService';
import { IDisposable } from 'vs/base/common/lifecycle';
import { KeyMod, KeyCode } from 'vs/base/common/keyCodes';
export type ServicesAccessor = InstantiationServicesAccessor;
@@ -139,6 +142,66 @@ export abstract class Command {
//#endregion Command
//#region MultiplexingCommand
/**
* Potential override for a command.
*
* @return `true` if the command was successfully run. This stops other overrides from being executed.
*/
export type CommandImplementation = (accessor: ServicesAccessor, args: unknown) => boolean;
export class MultiCommand extends Command {
private readonly _implementations: [number, CommandImplementation][] = [];
/**
* A higher priority gets to be looked at first
*/
public addImplementation(priority: number, implementation: CommandImplementation): IDisposable {
this._implementations.push([priority, implementation]);
this._implementations.sort((a, b) => b[0] - a[0]);
return {
dispose: () => {
for (let i = 0; i < this._implementations.length; i++) {
if (this._implementations[i][1] === implementation) {
this._implementations.splice(i, 1);
return;
}
}
}
};
}
public runCommand(accessor: ServicesAccessor, args: any): void | Promise<void> {
for (const impl of this._implementations) {
if (impl[1](accessor, args)) {
return;
}
}
}
}
//#endregion
/**
* A command that delegates to another command's implementation.
*
* This lets different commands be registered but share the same implementation
*/
export class ProxyCommand extends Command {
constructor(
private readonly command: Command,
opts: ICommandOptions
) {
super(opts);
}
public runCommand(accessor: ServicesAccessor, args: any): void | Promise<void> {
return this.command.runCommand(accessor, args);
}
}
//#region EditorCommand
export interface IContributionCommandOptions<T> extends ICommandOptions {
@@ -379,8 +442,10 @@ export function registerEditorCommand<T extends EditorCommand>(editorCommand: T)
return editorCommand;
}
export function registerEditorAction(ctor: { new(): EditorAction; }): void {
EditorContributionRegistry.INSTANCE.registerEditorAction(new ctor());
export function registerEditorAction<T extends EditorAction>(ctor: { new(): T; }): T {
const action = new ctor();
EditorContributionRegistry.INSTANCE.registerEditorAction(action);
return action;
}
export function registerInstantiatedEditorAction(editorAction: EditorAction): void {
@@ -475,3 +540,75 @@ class EditorContributionRegistry {
}
Registry.add(Extensions.EditorCommonContributions, EditorContributionRegistry.INSTANCE);
function registerCommand<T extends Command>(command: T): T {
command.register();
return command;
}
export const UndoCommand = registerCommand(new MultiCommand({
id: 'undo',
precondition: undefined,
kbOpts: {
weight: KeybindingWeight.EditorCore,
primary: KeyMod.CtrlCmd | KeyCode.KEY_Z
},
menuOpts: [{
menuId: MenuId.MenubarEditMenu,
group: '1_do',
title: nls.localize({ key: 'miUndo', comment: ['&& denotes a mnemonic'] }, "&&Undo"),
order: 1
}, {
menuId: MenuId.CommandPalette,
group: '',
title: nls.localize('undo', "Undo"),
order: 1
}]
}));
registerCommand(new ProxyCommand(UndoCommand, { id: 'default:undo', precondition: undefined }));
export const RedoCommand = registerCommand(new MultiCommand({
id: 'redo',
precondition: undefined,
kbOpts: {
weight: KeybindingWeight.EditorCore,
primary: KeyMod.CtrlCmd | KeyCode.KEY_Y,
secondary: [KeyMod.CtrlCmd | KeyMod.Shift | KeyCode.KEY_Z],
mac: { primary: KeyMod.CtrlCmd | KeyMod.Shift | KeyCode.KEY_Z }
},
menuOpts: [{
menuId: MenuId.MenubarEditMenu,
group: '1_do',
title: nls.localize({ key: 'miRedo', comment: ['&& denotes a mnemonic'] }, "&&Redo"),
order: 2
}, {
menuId: MenuId.CommandPalette,
group: '',
title: nls.localize('redo', "Redo"),
order: 1
}]
}));
registerCommand(new ProxyCommand(RedoCommand, { id: 'default:redo', precondition: undefined }));
export const SelectAllCommand = registerCommand(new MultiCommand({
id: 'editor.action.selectAll',
precondition: undefined,
kbOpts: {
weight: KeybindingWeight.EditorCore,
kbExpr: null,
primary: KeyMod.CtrlCmd | KeyCode.KEY_A
},
menuOpts: [{
menuId: MenuId.MenubarEditMenu, // {{SQL CARBON EDIT}} - Put this in the edit menu since we disabled the selection menu
group: '4_find_global', // {{SQL CARBON EDIT}} - Put this in the edit menu since we disabled the selection menu
title: nls.localize({ key: 'miSelectAll', comment: ['&& denotes a mnemonic'] }, "&&Select All"),
order: 1
}, {
menuId: MenuId.CommandPalette,
group: '',
title: nls.localize('selectAll', "Select All"),
order: 1
}]
}));

View File

@@ -4,7 +4,7 @@
*--------------------------------------------------------------------------------------------*/
import { IKeyboardEvent } from 'vs/base/browser/keyboardEvent';
import { CoreEditorCommand, CoreNavigationCommands } from 'vs/editor/browser/controller/coreCommands';
import { CoreNavigationCommands } from 'vs/editor/browser/controller/coreCommands';
import { IEditorMouseEvent, IPartialEditorMouseEvent } from 'vs/editor/browser/editorBrowser';
import { ViewUserInputEvents } from 'vs/editor/browser/view/viewUserInputEvents';
import { Position } from 'vs/editor/common/core/position';
@@ -35,8 +35,6 @@ export interface IMouseDispatchData {
}
export interface ICommandDelegate {
executeEditorCommand(editorCommand: CoreEditorCommand, args: any): void;
paste(text: string, pasteOnNewLine: boolean, multicursorText: string[] | null, mode: string | null): void;
type(text: string): void;
replacePreviousChar(text: string, replaceCharCnt: number): void;
@@ -64,11 +62,6 @@ export class ViewController {
this.commandDelegate = commandDelegate;
}
private _execMouseCommand(editorCommand: CoreEditorCommand, args: any): void {
args.source = 'mouse';
this.commandDelegate.executeEditorCommand(editorCommand, args);
}
public paste(text: string, pasteOnNewLine: boolean, multicursorText: string[] | null, mode: string | null): void {
this.commandDelegate.paste(text, pasteOnNewLine, multicursorText, mode);
}
@@ -94,7 +87,7 @@ export class ViewController {
}
public setSelection(modelSelection: Selection): void {
this.commandDelegate.executeEditorCommand(CoreNavigationCommands.SetSelection, {
CoreNavigationCommands.SetSelection.runCoreEditorCommand(this.viewModel, {
source: 'keyboard',
selection: modelSelection
});
@@ -214,22 +207,24 @@ export class ViewController {
private _usualArgs(viewPosition: Position) {
viewPosition = this._validateViewColumn(viewPosition);
return {
source: 'mouse',
position: this._convertViewToModelPosition(viewPosition),
viewPosition: viewPosition
};
}
public moveTo(viewPosition: Position): void {
this._execMouseCommand(CoreNavigationCommands.MoveTo, this._usualArgs(viewPosition));
CoreNavigationCommands.MoveTo.runCoreEditorCommand(this.viewModel, this._usualArgs(viewPosition));
}
private _moveToSelect(viewPosition: Position): void {
this._execMouseCommand(CoreNavigationCommands.MoveToSelect, this._usualArgs(viewPosition));
CoreNavigationCommands.MoveToSelect.runCoreEditorCommand(this.viewModel, this._usualArgs(viewPosition));
}
private _columnSelect(viewPosition: Position, mouseColumn: number, doColumnSelect: boolean): void {
viewPosition = this._validateViewColumn(viewPosition);
this._execMouseCommand(CoreNavigationCommands.ColumnSelect, {
CoreNavigationCommands.ColumnSelect.runCoreEditorCommand(this.viewModel, {
source: 'mouse',
position: this._convertViewToModelPosition(viewPosition),
viewPosition: viewPosition,
mouseColumn: mouseColumn,
@@ -239,7 +234,8 @@ export class ViewController {
private _createCursor(viewPosition: Position, wholeLine: boolean): void {
viewPosition = this._validateViewColumn(viewPosition);
this._execMouseCommand(CoreNavigationCommands.CreateCursor, {
CoreNavigationCommands.CreateCursor.runCoreEditorCommand(this.viewModel, {
source: 'mouse',
position: this._convertViewToModelPosition(viewPosition),
viewPosition: viewPosition,
wholeLine: wholeLine
@@ -247,39 +243,39 @@ export class ViewController {
}
private _lastCursorMoveToSelect(viewPosition: Position): void {
this._execMouseCommand(CoreNavigationCommands.LastCursorMoveToSelect, this._usualArgs(viewPosition));
CoreNavigationCommands.LastCursorMoveToSelect.runCoreEditorCommand(this.viewModel, this._usualArgs(viewPosition));
}
private _wordSelect(viewPosition: Position): void {
this._execMouseCommand(CoreNavigationCommands.WordSelect, this._usualArgs(viewPosition));
CoreNavigationCommands.WordSelect.runCoreEditorCommand(this.viewModel, this._usualArgs(viewPosition));
}
private _wordSelectDrag(viewPosition: Position): void {
this._execMouseCommand(CoreNavigationCommands.WordSelectDrag, this._usualArgs(viewPosition));
CoreNavigationCommands.WordSelectDrag.runCoreEditorCommand(this.viewModel, this._usualArgs(viewPosition));
}
private _lastCursorWordSelect(viewPosition: Position): void {
this._execMouseCommand(CoreNavigationCommands.LastCursorWordSelect, this._usualArgs(viewPosition));
CoreNavigationCommands.LastCursorWordSelect.runCoreEditorCommand(this.viewModel, this._usualArgs(viewPosition));
}
private _lineSelect(viewPosition: Position): void {
this._execMouseCommand(CoreNavigationCommands.LineSelect, this._usualArgs(viewPosition));
CoreNavigationCommands.LineSelect.runCoreEditorCommand(this.viewModel, this._usualArgs(viewPosition));
}
private _lineSelectDrag(viewPosition: Position): void {
this._execMouseCommand(CoreNavigationCommands.LineSelectDrag, this._usualArgs(viewPosition));
CoreNavigationCommands.LineSelectDrag.runCoreEditorCommand(this.viewModel, this._usualArgs(viewPosition));
}
private _lastCursorLineSelect(viewPosition: Position): void {
this._execMouseCommand(CoreNavigationCommands.LastCursorLineSelect, this._usualArgs(viewPosition));
CoreNavigationCommands.LastCursorLineSelect.runCoreEditorCommand(this.viewModel, this._usualArgs(viewPosition));
}
private _lastCursorLineSelectDrag(viewPosition: Position): void {
this._execMouseCommand(CoreNavigationCommands.LastCursorLineSelectDrag, this._usualArgs(viewPosition));
CoreNavigationCommands.LastCursorLineSelectDrag.runCoreEditorCommand(this.viewModel, this._usualArgs(viewPosition));
}
private _selectAll(): void {
this._execMouseCommand(CoreNavigationCommands.SelectAll, {});
CoreNavigationCommands.SelectAll.runCoreEditorCommand(this.viewModel, { source: 'mouse' });
}
// ----------------------

View File

@@ -15,7 +15,6 @@ import { hash } from 'vs/base/common/hash';
import { Disposable, IDisposable, dispose } from 'vs/base/common/lifecycle';
import { Schemas } from 'vs/base/common/network';
import { Configuration } from 'vs/editor/browser/config/configuration';
import { CoreEditorCommand } from 'vs/editor/browser/controller/coreCommands';
import * as editorBrowser from 'vs/editor/browser/editorBrowser';
import { EditorExtensionsRegistry, IEditorContributionDescription } from 'vs/editor/browser/editorExtensions';
import { ICodeEditorService } from 'vs/editor/browser/services/codeEditorService';
@@ -1552,9 +1551,6 @@ export class CodeEditorWidget extends Disposable implements editorBrowser.ICodeE
let commandDelegate: ICommandDelegate;
if (this.isSimpleWidget) {
commandDelegate = {
executeEditorCommand: (editorCommand: CoreEditorCommand, args: any): void => {
editorCommand.runCoreEditorCommand(viewModel, args);
},
paste: (text: string, pasteOnNewLine: boolean, multicursorText: string[] | null, mode: string | null) => {
this._paste('keyboard', text, pasteOnNewLine, multicursorText, mode);
},
@@ -1576,9 +1572,6 @@ export class CodeEditorWidget extends Disposable implements editorBrowser.ICodeE
};
} else {
commandDelegate = {
executeEditorCommand: (editorCommand: CoreEditorCommand, args: any): void => {
editorCommand.runCoreEditorCommand(viewModel, args);
},
paste: (text: string, pasteOnNewLine: boolean, multicursorText: string[] | null, mode: string | null) => {
const payload: editorCommon.PastePayload = { text, pasteOnNewLine, multicursorText, mode };
this._commandService.executeCommand(editorCommon.Handler.Paste, payload);
@@ -2018,5 +2011,5 @@ registerThemingParticipant((theme, collector) => {
}
const deprecatedForeground = theme.getColor(editorForeground) || 'inherit';
collector.addRule(`.monaco-editor .${ClassName.EditorDeprecatedInlineDecoration} { text-decoration: line-through; text-decoration-color: ${deprecatedForeground}}`);
collector.addRule(`.monaco-editor.showDeprecated .${ClassName.EditorDeprecatedInlineDecoration} { text-decoration: line-through; text-decoration-color: ${deprecatedForeground}}`);
});

View File

@@ -503,8 +503,13 @@ const editorConfiguration: IConfigurationNode = {
description: nls.localize('wordBasedSuggestions', "Controls whether completions should be computed based on words in the document.")
},
'editor.semanticHighlighting.enabled': {
type: 'boolean',
default: true,
enum: [true, false, 'configuredByTheme'],
enumDescriptions: [
nls.localize('semanticHighlighting.true', 'Semantic highlighting enabled for all color themes.'),
nls.localize('semanticHighlighting.false', 'Semantic highlighting disabled for all color themes.'),
nls.localize('semanticHighlighting.configuredByTheme', 'Semantic highlighting is configured by the current color theme\'s `semanticHighlighting` setting.')
],
default: 'configuredByTheme',
description: nls.localize('semanticHighlighting.enabled', "Controls whether the semanticHighlighting is shown for the languages that support it.")
},
'editor.stablePeek': {

View File

@@ -594,6 +594,10 @@ export interface IEditorOptions {
* Defaults to false.
*/
definitionLinkOpensInPeek?: boolean;
/**
* Controls strikethrough deprecated variables.
*/
showDeprecated?: boolean;
}
export interface IEditorConstructionOptions extends IEditorOptions {
@@ -1219,22 +1223,28 @@ class EditorClassName extends ComputedEditorOption<EditorOption.editorClassName,
}
public compute(env: IEnvironmentalOptions, options: IComputedEditorOptions, _: string): string {
let className = 'monaco-editor';
const classNames = ['monaco-editor'];
if (options.get(EditorOption.extraEditorClassName)) {
className += ' ' + options.get(EditorOption.extraEditorClassName);
classNames.push(options.get(EditorOption.extraEditorClassName));
}
if (env.extraEditorClassName) {
className += ' ' + env.extraEditorClassName;
classNames.push(env.extraEditorClassName);
}
if (options.get(EditorOption.mouseStyle) === 'default') {
className += ' mouse-default';
classNames.push('mouse-default');
} else if (options.get(EditorOption.mouseStyle) === 'copy') {
className += ' mouse-copy';
classNames.push('mouse-copy');
}
if (options.get(EditorOption.showUnused)) {
className += ' showUnused';
classNames.push('showUnused');
}
return className;
if (options.get(EditorOption.showDeprecated)) {
classNames.push('showDeprecated');
}
return classNames.join(' ');
}
}
@@ -3599,6 +3609,7 @@ export const enum EditorOption {
wordWrapMinified,
wrappingIndent,
wrappingStrategy,
showDeprecated,
// Leave these at the end (because they have dependencies!)
editorClassName,
@@ -4085,6 +4096,10 @@ export const EditorOptions = {
EditorOption.showUnused, 'showUnused', true,
{ description: nls.localize('showUnused', "Controls fading out of unused code.") }
)),
showDeprecated: register(new EditorBooleanOption(
EditorOption.showDeprecated, 'showDeprecated', true,
{ description: nls.localize('showDeprecated', "Controls strikethrough deprecated variables.") }
)),
snippetSuggestions: register(new EditorStringEnumOption(
EditorOption.snippetSuggestions, 'snippetSuggestions',
'inline' as 'top' | 'bottom' | 'inline' | 'none',

View File

@@ -163,11 +163,9 @@ export class WordOperations {
public static moveWordLeft(wordSeparators: WordCharacterClassifier, model: ICursorSimpleModel, position: Position, wordNavigationType: WordNavigationType): Position {
let lineNumber = position.lineNumber;
let column = position.column;
let movedToPreviousLine = false;
if (column === 1) {
if (lineNumber > 1) {
movedToPreviousLine = true;
lineNumber = lineNumber - 1;
column = model.getLineMaxColumn(lineNumber);
}
@@ -176,17 +174,6 @@ export class WordOperations {
let prevWordOnLine = WordOperations._findPreviousWordOnLine(wordSeparators, model, new Position(lineNumber, column));
if (wordNavigationType === WordNavigationType.WordStart) {
if (prevWordOnLine && !movedToPreviousLine) {
// Special case for Visual Studio compatibility:
// when starting in the trim whitespace at the end of a line,
// go to the end of the last word
const lastWhitespaceColumn = model.getLineLastNonWhitespaceColumn(lineNumber);
if (lastWhitespaceColumn < column) {
return new Position(lineNumber, prevWordOnLine.end + 1);
}
}
return new Position(lineNumber, prevWordOnLine ? prevWordOnLine.start + 1 : 1);
}

View File

@@ -41,7 +41,6 @@ export class InternalEditorAction implements IEditorAction {
return Promise.resolve(undefined);
}
const r = this._run();
return r ? r : Promise.resolve(undefined);
return this._run();
}
}

View File

@@ -35,7 +35,7 @@ import { VSBufferReadableStream, VSBuffer } from 'vs/base/common/buffer';
import { TokensStore, MultilineTokens, countEOL, MultilineTokens2, TokensStore2 } from 'vs/editor/common/model/tokensStore';
import { Color } from 'vs/base/common/color';
import { EditorTheme } from 'vs/editor/common/view/viewContext';
import { IUndoRedoService } from 'vs/platform/undoRedo/common/undoRedo';
import { IUndoRedoService, ResourceEditStackSnapshot } from 'vs/platform/undoRedo/common/undoRedo';
import { TextChange } from 'vs/editor/common/model/textChange';
import { Constants } from 'vs/base/common/uint';
@@ -278,6 +278,7 @@ export class TextModel extends Disposable implements model.ITextModel {
* Unlike, versionId, this can go down (via undo) or go to previous values (via redo)
*/
private _alternativeVersionId: number;
private _initialUndoRedoSnapshot: ResourceEditStackSnapshot | null;
private readonly _isTooLargeForSyncing: boolean;
private readonly _isTooLargeForTokenization: boolean;
@@ -351,6 +352,7 @@ export class TextModel extends Disposable implements model.ITextModel {
this._versionId = 1;
this._alternativeVersionId = 1;
this._initialUndoRedoSnapshot = null;
this._isDisposed = false;
this._isDisposing = false;
@@ -719,6 +721,11 @@ export class TextModel extends Disposable implements model.ITextModel {
return this._alternativeVersionId;
}
public getInitialUndoRedoSnapshot(): ResourceEditStackSnapshot | null {
this._assertNotDisposed();
return this._initialUndoRedoSnapshot;
}
public getOffsetAt(rawPosition: IPosition): number {
this._assertNotDisposed();
let position = this._validatePosition(rawPosition.lineNumber, rawPosition.column, StringOffsetValidationType.Relaxed);
@@ -744,6 +751,10 @@ export class TextModel extends Disposable implements model.ITextModel {
this._alternativeVersionId = newAlternativeVersionId;
}
public _overwriteInitialUndoRedoSnapshot(newInitialUndoRedoSnapshot: ResourceEditStackSnapshot | null): void {
this._initialUndoRedoSnapshot = newInitialUndoRedoSnapshot;
}
public getValue(eol?: model.EndOfLinePreference, preserveBOM: boolean = false): string {
this._assertNotDisposed();
const fullModelRange = this.getFullModelRange();
@@ -1187,6 +1198,9 @@ export class TextModel extends Disposable implements model.ITextModel {
try {
this._onDidChangeDecorations.beginDeferredEmit();
this._eventEmitter.beginDeferredEmit();
if (this._initialUndoRedoSnapshot === null) {
this._initialUndoRedoSnapshot = this._undoRedoService.createSnapshot(this.uri);
}
this._commandManager.pushEOL(eol);
} finally {
this._eventEmitter.endDeferredEmit();
@@ -1311,6 +1325,9 @@ export class TextModel extends Disposable implements model.ITextModel {
this._trimAutoWhitespaceLines = null;
}
if (this._initialUndoRedoSnapshot === null) {
this._initialUndoRedoSnapshot = this._undoRedoService.createSnapshot(this.uri);
}
return this._commandManager.pushEditOperation(beforeCursorState, editOperations, cursorStateComputer);
}

View File

@@ -548,8 +548,12 @@ export class Searcher {
if (matchStartIndex === this._prevMatchStartIndex && matchLength === this._prevMatchLength) {
if (matchLength === 0) {
// the search result is an empty string and won't advance `regex.lastIndex`, so `regex.exec` will stuck here
// we attempt to recover from that by advancing by one
this._searchRegex.lastIndex += 1;
// we attempt to recover from that by advancing by two if surrogate pair found and by one otherwise
if (strings.getNextCodePoint(text, textLength, this._searchRegex.lastIndex) > 0xFFFF) {
this._searchRegex.lastIndex += 2;
} else {
this._searchRegex.lastIndex += 1;
}
continue;
}
// Exit early if the regex matches the same range twice

View File

@@ -5,6 +5,7 @@
import { IRelativePattern, match as matchGlobPattern } from 'vs/base/common/glob';
import { URI } from 'vs/base/common/uri'; // TODO@Alex
import { normalize } from 'vs/base/common/path';
export interface LanguageFilter {
language?: string;
@@ -83,7 +84,19 @@ export function score(selector: LanguageSelector | undefined, candidateUri: URI,
}
if (pattern) {
if (pattern === candidateUri.fsPath || matchGlobPattern(pattern, candidateUri.fsPath)) {
let normalizedPattern: string | IRelativePattern;
if (typeof pattern === 'string') {
normalizedPattern = pattern;
} else {
// Since this pattern has a `base` property, we need
// to normalize this path first before passing it on
// because we will compare it against `Uri.fsPath`
// which uses platform specific separators.
// Refs: https://github.com/microsoft/vscode/issues/99938
normalizedPattern = { ...pattern, base: normalize(pattern.base) };
}
if (normalizedPattern === candidateUri.fsPath || matchGlobPattern(normalizedPattern, candidateUri.fsPath)) {
ret = 10;
} else {
return 0;

View File

@@ -154,7 +154,7 @@ function getClassifier(): CharacterClassifier<CharacterClass> {
if (_classifier === null) {
_classifier = new CharacterClassifier<CharacterClass>(CharacterClass.None);
const FORCE_TERMINATION_CHARACTERS = ' \t<>\'\"、。。、,.:;‘“〈《「『【〔([{「」}])〕】』」》〉”’`~…';
const FORCE_TERMINATION_CHARACTERS = ' \t<>\'\"、。。、,.:;‘“〈《「『【〔([{「」}])〕】』」》〉”’`~…';
for (let i = 0; i < FORCE_TERMINATION_CHARACTERS.length; i++) {
_classifier.set(FORCE_TERMINATION_CHARACTERS.charCodeAt(i), CharacterClass.ForceTermination);
}

View File

@@ -22,6 +22,7 @@ import { regExpFlags } from 'vs/base/common/strings';
import { isNonEmptyArray } from 'vs/base/common/arrays';
import { ILogService } from 'vs/platform/log/common/log';
import { StopWatch } from 'vs/base/common/stopwatch';
import { canceled } from 'vs/base/common/errors';
/**
* Stop syncing a model to the worker if it was not needed for 1 min.
@@ -380,6 +381,7 @@ export class EditorWorkerClient extends Disposable {
private _worker: IWorkerClient<EditorSimpleWorker> | null;
private readonly _workerFactory: DefaultWorkerFactory;
private _modelManager: EditorModelManager | null;
private _disposed = false;
constructor(modelService: IModelService, keepIdleModels: boolean, label: string | undefined) {
super();
@@ -427,6 +429,9 @@ export class EditorWorkerClient extends Disposable {
}
protected _withSyncedResources(resources: URI[]): Promise<EditorSimpleWorker> {
if (this._disposed) {
return Promise.reject(canceled());
}
return this._getProxy().then((proxy) => {
this._getOrCreateModelManager(proxy).ensureSyncedResources(resources);
return proxy;
@@ -495,4 +500,9 @@ export class EditorWorkerClient extends Disposable {
return proxy.navigateValueSet(resource.toString(), range, up, wordDef, wordDefFlags);
});
}
dispose(): void {
super.dispose();
this._disposed = true;
}
}

View File

@@ -24,14 +24,14 @@ import { RunOnceScheduler } from 'vs/base/common/async';
import { CancellationTokenSource } from 'vs/base/common/cancellation';
import { IThemeService } from 'vs/platform/theme/common/themeService';
import { ILogService } from 'vs/platform/log/common/log';
import { IUndoRedoService, IUndoRedoElement, IPastFutureElements } from 'vs/platform/undoRedo/common/undoRedo';
import { IUndoRedoService, IUndoRedoElement, IPastFutureElements, ResourceEditStackSnapshot } from 'vs/platform/undoRedo/common/undoRedo';
import { StringSHA1 } from 'vs/base/common/hash';
import { SingleModelEditStackElement, MultiModelEditStackElement, EditStackElement, isEditStackElement } from 'vs/editor/common/model/editStack';
import { Schemas } from 'vs/base/common/network';
import { SemanticTokensProviderStyling, toMultilineTokens2 } from 'vs/editor/common/services/semanticTokensProviderStyling';
export interface IEditorSemanticHighlightingOptions {
enabled?: boolean;
enabled: true | false | 'configuredByTheme';
}
function MODEL_ID(resource: URI): string {
@@ -51,7 +51,7 @@ function computeModelSha1(model: ITextModel): string {
class ModelData implements IDisposable {
public readonly model: ITextModel;
public readonly model: TextModel;
private _languageSelection: ILanguageSelection | null;
private _languageSelectionListener: IDisposable | null;
@@ -59,7 +59,7 @@ class ModelData implements IDisposable {
private readonly _modelEventListeners = new DisposableStore();
constructor(
model: ITextModel,
model: TextModel,
onWillDispose: (model: ITextModel) => void,
onDidChangeLanguage: (model: ITextModel, e: IModelLanguageChangedEvent) => void
) {
@@ -138,6 +138,7 @@ function isEditStackElements(elements: IUndoRedoElement[]): elements is EditStac
class DisposedModelInfo {
constructor(
public readonly uri: URI,
public readonly initialUndoRedoSnapshot: ResourceEditStackSnapshot | null,
public readonly time: number,
public readonly sharesUndoRedoStack: boolean,
public readonly heapSize: number,
@@ -362,7 +363,9 @@ export class ModelServiceImpl extends Disposable implements IModelService {
while (disposedModels.length > 0 && this._disposedModelsHeapSize > maxModelsHeapSize) {
const disposedModel = disposedModels.shift()!;
this._removeDisposedModel(disposedModel.uri);
this._undoRedoService.removeElements(disposedModel.uri);
if (disposedModel.initialUndoRedoSnapshot !== null) {
this._undoRedoService.restoreSnapshot(disposedModel.initialUndoRedoSnapshot);
}
}
}
}
@@ -390,9 +393,12 @@ export class ModelServiceImpl extends Disposable implements IModelService {
if (sha1IsEqual) {
model._overwriteVersionId(disposedModelData.versionId);
model._overwriteAlternativeVersionId(disposedModelData.alternativeVersionId);
model._overwriteInitialUndoRedoSnapshot(disposedModelData.initialUndoRedoSnapshot);
}
} else {
this._undoRedoService.removeElements(resource);
if (disposedModelData.initialUndoRedoSnapshot !== null) {
this._undoRedoService.restoreSnapshot(disposedModelData.initialUndoRedoSnapshot);
}
}
}
const modelId = MODEL_ID(model.uri);
@@ -541,7 +547,10 @@ export class ModelServiceImpl extends Disposable implements IModelService {
if (!maintainUndoRedoStack) {
if (!sharesUndoRedoStack) {
this._undoRedoService.removeElements(resource);
const initialUndoRedoSnapshot = modelData.model.getInitialUndoRedoSnapshot();
if (initialUndoRedoSnapshot !== null) {
this._undoRedoService.restoreSnapshot(initialUndoRedoSnapshot);
}
}
modelData.model.dispose();
return;
@@ -550,7 +559,10 @@ export class ModelServiceImpl extends Disposable implements IModelService {
const maxMemory = ModelServiceImpl.MAX_MEMORY_FOR_CLOSED_FILES_UNDO_STACK;
if (!sharesUndoRedoStack && heapSize > maxMemory) {
// the undo stack for this file would never fit in the configured memory, so don't bother with it.
this._undoRedoService.removeElements(resource);
const initialUndoRedoSnapshot = modelData.model.getInitialUndoRedoSnapshot();
if (initialUndoRedoSnapshot !== null) {
this._undoRedoService.restoreSnapshot(initialUndoRedoSnapshot);
}
modelData.model.dispose();
return;
}
@@ -559,7 +571,7 @@ export class ModelServiceImpl extends Disposable implements IModelService {
// We only invalidate the elements, but they remain in the undo-redo service.
this._undoRedoService.setElementsValidFlag(resource, false, (element) => (isEditStackElement(element) && element.matchesResource(resource)));
this._insertDisposedModel(new DisposedModelInfo(resource, Date.now(), sharesUndoRedoStack, heapSize, computeModelSha1(model), model.getVersionId(), model.getAlternativeVersionId()));
this._insertDisposedModel(new DisposedModelInfo(resource, modelData.model.getInitialUndoRedoSnapshot(), Date.now(), sharesUndoRedoStack, heapSize, computeModelSha1(model), model.getVersionId(), model.getAlternativeVersionId()));
modelData.model.dispose();
}
@@ -621,11 +633,11 @@ export interface ILineSequence {
export const SEMANTIC_HIGHLIGHTING_SETTING_ID = 'editor.semanticHighlighting';
export function isSemanticColoringEnabled(model: ITextModel, themeService: IThemeService, configurationService: IConfigurationService): boolean {
if (!themeService.getColorTheme().semanticHighlighting) {
return false;
const setting = configurationService.getValue<IEditorSemanticHighlightingOptions>(SEMANTIC_HIGHLIGHTING_SETTING_ID, { overrideIdentifier: model.getLanguageIdentifier().language, resource: model.uri })?.enabled;
if (typeof setting === 'boolean') {
return setting;
}
const options = configurationService.getValue<IEditorSemanticHighlightingOptions>(SEMANTIC_HIGHLIGHTING_SETTING_ID, { overrideIdentifier: model.getLanguageIdentifier().language, resource: model.uri });
return Boolean(options && options.enabled);
return themeService.getColorTheme().semanticHighlighting;
}
class SemanticColoringFeature extends Disposable {

View File

@@ -279,11 +279,12 @@ export enum EditorOption {
wordWrapMinified = 109,
wrappingIndent = 110,
wrappingStrategy = 111,
editorClassName = 112,
pixelRatio = 113,
tabFocusMode = 114,
layoutInfo = 115,
wrappingInfo = 116
showDeprecated = 112,
editorClassName = 113,
pixelRatio = 114,
tabFocusMode = 115,
layoutInfo = 116,
wrappingInfo = 117
}
/**

View File

@@ -210,12 +210,12 @@ export class ViewLayout extends Disposable implements IViewLayout {
const width = layoutInfo.contentWidth;
const height = layoutInfo.height;
const scrollDimensions = this._scrollable.getScrollDimensions();
const scrollWidth = scrollDimensions.scrollWidth;
const contentWidth = scrollDimensions.contentWidth;
this._scrollable.setScrollDimensions(new EditorScrollDimensions(
width,
scrollDimensions.contentWidth,
height,
this._getContentHeight(width, height, scrollWidth)
this._getContentHeight(width, height, contentWidth)
));
} else {
this._updateHeight();
@@ -250,14 +250,14 @@ export class ViewLayout extends Disposable implements IViewLayout {
return scrollbar.horizontalScrollbarSize;
}
private _getContentHeight(width: number, height: number, scrollWidth: number): number {
private _getContentHeight(width: number, height: number, contentWidth: number): number {
const options = this._configuration.options;
let result = this._linesLayout.getLinesTotalHeight();
if (options.get(EditorOption.scrollBeyondLastLine)) {
result += height - options.get(EditorOption.lineHeight);
} else {
result += this._getHorizontalScrollbarHeight(width, scrollWidth);
result += this._getHorizontalScrollbarHeight(width, contentWidth);
}
return result;
@@ -267,12 +267,12 @@ export class ViewLayout extends Disposable implements IViewLayout {
const scrollDimensions = this._scrollable.getScrollDimensions();
const width = scrollDimensions.width;
const height = scrollDimensions.height;
const scrollWidth = scrollDimensions.scrollWidth;
const contentWidth = scrollDimensions.contentWidth;
this._scrollable.setScrollDimensions(new EditorScrollDimensions(
width,
scrollDimensions.contentWidth,
height,
this._getContentHeight(width, height, scrollWidth)
this._getContentHeight(width, height, contentWidth)
));
}

View File

@@ -9,7 +9,7 @@ import { KeyCode, KeyMod } from 'vs/base/common/keyCodes';
import * as platform from 'vs/base/common/platform';
import { CopyOptions } from 'vs/editor/browser/controller/textAreaInput';
import { ICodeEditor } from 'vs/editor/browser/editorBrowser';
import { EditorAction, IActionOptions, ICommandKeybindingsOptions, registerEditorAction } from 'vs/editor/browser/editorExtensions';
import { EditorAction, registerEditorAction, Command, MultiCommand } from 'vs/editor/browser/editorExtensions';
import { ICodeEditorService } from 'vs/editor/browser/services/codeEditorService';
import { EditorContextKeys } from 'vs/editor/common/editorContextKeys';
import { MenuId } from 'vs/platform/actions/common/actions';
@@ -28,171 +28,108 @@ const supportsCopyWithSyntaxHighlighting = (supportsCopy && !browser.isEdge);
// privileges to actually perform the action
const supportsPaste = (platform.isNative || (!browser.isChrome && document.queryCommandSupported('paste')));
type ExecCommand = 'cut' | 'copy' | 'paste';
abstract class ExecCommandAction extends EditorAction {
private readonly browserCommand: ExecCommand;
constructor(browserCommand: ExecCommand, opts: IActionOptions) {
super(opts);
this.browserCommand = browserCommand;
}
public runCommand(accessor: ServicesAccessor, args: any): void {
let focusedEditor = accessor.get(ICodeEditorService).getFocusedCodeEditor();
// Only if editor text focus (i.e. not if editor has widget focus).
if (focusedEditor && focusedEditor.hasTextFocus()) {
focusedEditor.trigger('keyboard', this.id, args);
return;
}
document.execCommand(this.browserCommand);
}
public run(accessor: ServicesAccessor, editor: ICodeEditor): void {
editor.focus();
document.execCommand(this.browserCommand);
}
function registerCommand<T extends Command>(command: T): T {
command.register();
return command;
}
class ExecCommandCutAction extends ExecCommandAction {
constructor() {
let kbOpts: ICommandKeybindingsOptions | undefined = {
kbExpr: EditorContextKeys.textInputFocus,
export const CutAction = supportsCut ? registerCommand(new MultiCommand({
id: 'editor.action.clipboardCutAction',
precondition: undefined,
kbOpts: (
// Do not bind cut keybindings in the browser,
// since browsers do that for us and it avoids security prompts
platform.isNative ? {
primary: KeyMod.CtrlCmd | KeyCode.KEY_X,
win: { primary: KeyMod.CtrlCmd | KeyCode.KEY_X, secondary: [KeyMod.Shift | KeyCode.Delete] },
weight: KeybindingWeight.EditorContrib
};
// Do not bind cut keybindings in the browser,
} : undefined
),
menuOpts: [{
menuId: MenuId.MenubarEditMenu,
group: '2_ccp',
title: nls.localize({ key: 'miCut', comment: ['&& denotes a mnemonic'] }, "Cu&&t"),
order: 1
}, {
menuId: MenuId.EditorContext,
group: CLIPBOARD_CONTEXT_MENU_GROUP,
title: nls.localize('actions.clipboard.cutLabel', "Cut"),
when: EditorContextKeys.writable,
order: 1,
}, {
menuId: MenuId.CommandPalette,
group: '',
title: nls.localize('actions.clipboard.cutLabel', "Cut"),
order: 1
}]
})) : undefined;
export const CopyAction = supportsCopy ? registerCommand(new MultiCommand({
id: 'editor.action.clipboardCopyAction',
precondition: undefined,
kbOpts: (
// Do not bind copy keybindings in the browser,
// since browsers do that for us and it avoids security prompts
if (!platform.isNative) {
kbOpts = undefined;
}
super('cut', {
id: 'editor.action.clipboardCutAction',
label: nls.localize('actions.clipboard.cutLabel', "Cut"),
alias: 'Cut',
precondition: EditorContextKeys.writable,
kbOpts: kbOpts,
contextMenuOpts: {
group: CLIPBOARD_CONTEXT_MENU_GROUP,
order: 1
},
menuOpts: {
menuId: MenuId.MenubarEditMenu,
group: '2_ccp',
title: nls.localize({ key: 'miCut', comment: ['&& denotes a mnemonic'] }, "Cu&&t"),
order: 1
}
});
}
public run(accessor: ServicesAccessor, editor: ICodeEditor): void {
if (!editor.hasModel()) {
return;
}
const emptySelectionClipboard = editor.getOption(EditorOption.emptySelectionClipboard);
if (!emptySelectionClipboard && editor.getSelection().isEmpty()) {
return;
}
super.run(accessor, editor);
}
}
class ExecCommandCopyAction extends ExecCommandAction {
constructor() {
let kbOpts: ICommandKeybindingsOptions | undefined = {
kbExpr: EditorContextKeys.textInputFocus,
platform.isNative ? {
primary: KeyMod.CtrlCmd | KeyCode.KEY_C,
win: { primary: KeyMod.CtrlCmd | KeyCode.KEY_C, secondary: [KeyMod.CtrlCmd | KeyCode.Insert] },
weight: KeybindingWeight.EditorContrib
};
// Do not bind copy keybindings in the browser,
} : undefined
),
menuOpts: [{
menuId: MenuId.MenubarEditMenu,
group: '2_ccp',
title: nls.localize({ key: 'miCopy', comment: ['&& denotes a mnemonic'] }, "&&Copy"),
order: 2
}, {
menuId: MenuId.EditorContext,
group: CLIPBOARD_CONTEXT_MENU_GROUP,
title: nls.localize('actions.clipboard.copyLabel', "Copy"),
order: 2,
}, {
menuId: MenuId.CommandPalette,
group: '',
title: nls.localize('actions.clipboard.copyLabel', "Copy"),
order: 1
}]
})) : undefined;
export const PasteAction = supportsPaste ? registerCommand(new MultiCommand({
id: 'editor.action.clipboardPasteAction',
precondition: undefined,
kbOpts: (
// Do not bind paste keybindings in the browser,
// since browsers do that for us and it avoids security prompts
if (!platform.isNative) {
kbOpts = undefined;
}
super('copy', {
id: 'editor.action.clipboardCopyAction',
label: nls.localize('actions.clipboard.copyLabel', "Copy"),
alias: 'Copy',
precondition: undefined,
kbOpts: kbOpts,
contextMenuOpts: {
group: CLIPBOARD_CONTEXT_MENU_GROUP,
order: 2
},
menuOpts: {
menuId: MenuId.MenubarEditMenu,
group: '2_ccp',
title: nls.localize({ key: 'miCopy', comment: ['&& denotes a mnemonic'] }, "&&Copy"),
order: 2
}
});
}
public run(accessor: ServicesAccessor, editor: ICodeEditor): void {
if (!editor.hasModel()) {
return;
}
const emptySelectionClipboard = editor.getOption(EditorOption.emptySelectionClipboard);
if (!emptySelectionClipboard && editor.getSelection().isEmpty()) {
return;
}
super.run(accessor, editor);
}
}
class ExecCommandPasteAction extends ExecCommandAction {
constructor() {
let kbOpts: ICommandKeybindingsOptions | undefined = {
kbExpr: EditorContextKeys.textInputFocus,
platform.isNative ? {
primary: KeyMod.CtrlCmd | KeyCode.KEY_V,
win: { primary: KeyMod.CtrlCmd | KeyCode.KEY_V, secondary: [KeyMod.Shift | KeyCode.Insert] },
linux: { primary: KeyMod.CtrlCmd | KeyCode.KEY_V, secondary: [KeyMod.Shift | KeyCode.Insert] },
weight: KeybindingWeight.EditorContrib
};
// Do not bind paste keybindings in the browser,
// since browsers do that for us and it avoids security prompts
if (!platform.isNative) {
kbOpts = undefined;
}
} : undefined
),
menuOpts: [{
menuId: MenuId.MenubarEditMenu,
group: '2_ccp',
title: nls.localize({ key: 'miPaste', comment: ['&& denotes a mnemonic'] }, "&&Paste"),
order: 3
}, {
menuId: MenuId.EditorContext,
group: CLIPBOARD_CONTEXT_MENU_GROUP,
title: nls.localize('actions.clipboard.pasteLabel', "Paste"),
when: EditorContextKeys.writable,
order: 3,
}, {
menuId: MenuId.CommandPalette,
group: '',
title: nls.localize('actions.clipboard.pasteLabel', "Paste"),
order: 1
}]
})) : undefined;
super('paste', {
id: 'editor.action.clipboardPasteAction',
label: nls.localize('actions.clipboard.pasteLabel', "Paste"),
alias: 'Paste',
precondition: EditorContextKeys.writable,
kbOpts: kbOpts,
contextMenuOpts: {
group: CLIPBOARD_CONTEXT_MENU_GROUP,
order: 3
},
menuOpts: {
menuId: MenuId.MenubarEditMenu,
group: '2_ccp',
title: nls.localize({ key: 'miPaste', comment: ['&& denotes a mnemonic'] }, "&&Paste"),
order: 3
}
});
}
}
class ExecCommandCopyWithSyntaxHighlightingAction extends ExecCommandAction {
class ExecCommandCopyWithSyntaxHighlightingAction extends EditorAction {
constructor() {
super('copy', {
super({
id: 'editor.action.clipboardCopyWithSyntaxHighlightingAction',
label: nls.localize('actions.clipboard.copyWithSyntaxHighlightingLabel', "Copy With Syntax Highlighting"),
alias: 'Copy With Syntax Highlighting',
@@ -217,20 +154,48 @@ class ExecCommandCopyWithSyntaxHighlightingAction extends ExecCommandAction {
}
CopyOptions.forceCopyWithSyntaxHighlighting = true;
super.run(accessor, editor);
editor.focus();
document.execCommand('copy');
CopyOptions.forceCopyWithSyntaxHighlighting = false;
}
}
if (supportsCut) {
registerEditorAction(ExecCommandCutAction);
}
if (supportsCopy) {
registerEditorAction(ExecCommandCopyAction);
}
if (supportsPaste) {
registerEditorAction(ExecCommandPasteAction);
function registerExecCommandImpl(target: MultiCommand | undefined, browserCommand: 'cut' | 'copy' | 'paste'): void {
if (!target) {
return;
}
// 1. handle case when focus is in editor.
target.addImplementation(10000, (accessor: ServicesAccessor, args: any) => {
// Only if editor text focus (i.e. not if editor has widget focus).
const focusedEditor = accessor.get(ICodeEditorService).getFocusedCodeEditor();
if (focusedEditor && focusedEditor.hasTextFocus()) {
if (browserCommand === 'cut' || browserCommand === 'copy') {
// Do not execute if there is no selection and empty selection clipboard is off
const emptySelectionClipboard = focusedEditor.getOption(EditorOption.emptySelectionClipboard);
const selection = focusedEditor.getSelection();
if (selection && selection.isEmpty() && !emptySelectionClipboard) {
return true;
}
}
document.execCommand(browserCommand);
return true;
}
return false;
});
// 2. (default) handle case when focus is somewhere else.
target.addImplementation(0, (accessor: ServicesAccessor, args: any) => {
// Only if editor text focus (i.e. not if editor has widget focus).
document.execCommand(browserCommand);
return true;
});
}
registerExecCommandImpl(CutAction, 'cut');
registerExecCommandImpl(CopyAction, 'copy');
registerExecCommandImpl(PasteAction, 'paste');
if (supportsCopyWithSyntaxHighlighting) {
registerEditorAction(ExecCommandCopyWithSyntaxHighlightingAction);
}

View File

@@ -73,6 +73,9 @@ class ManagedCodeActionSet extends Disposable implements CodeActionSet {
}
}
const emptyCodeActionsResponse = { actions: [] as modes.CodeAction[], documentation: undefined };
export function getCodeActions(
model: ITextModel,
rangeOrSelection: Range | Selection,
@@ -100,7 +103,7 @@ export function getCodeActions(
}
if (cts.token.isCancellationRequested) {
return { actions: [] as modes.CodeAction[], documentation: undefined };
return emptyCodeActionsResponse;
}
const filteredActions = (providedCodeActions?.actions || []).filter(action => action && filtersAction(filter, action));
@@ -111,7 +114,7 @@ export function getCodeActions(
throw err;
}
onUnexpectedExternalError(err);
return { actions: [] as modes.CodeAction[], documentation: undefined };
return emptyCodeActionsResponse;
}
});

View File

@@ -214,8 +214,8 @@ export class CodeActionModel extends Disposable {
}
const actions = createCancelablePromise(token => getCodeActions(model, trigger.selection, trigger.trigger, Progress.None, token));
if (this._progressService && trigger.trigger.type === CodeActionTriggerType.Manual) {
this._progressService.showWhile(actions, 250);
if (trigger.trigger.type === CodeActionTriggerType.Manual) {
this._progressService?.showWhile(actions, 250);
}
this.setState(new CodeActionsState.Triggered(trigger.trigger, trigger.selection, trigger.position, actions));

View File

@@ -173,7 +173,7 @@ export class ColorDetector extends Disposable implements IEditorContribution {
for (let i = 0; i < colorData.length && decorations.length < MAX_DECORATORS; i++) {
const { red, green, blue, alpha } = colorData[i].colorInfo.color;
const rgba = new RGBA(Math.round(red * 255), Math.round(green * 255), Math.round(blue * 255), alpha);
let subKey = hash(rgba).toString(16);
let subKey = hash(`rgba(${rgba.r},${rgba.g},${rgba.b},${rgba.a})`).toString(16);
let color = `rgba(${rgba.r}, ${rgba.g}, ${rgba.b}, ${rgba.a})`;
let key = 'colorBox-' + subKey;

View File

@@ -255,7 +255,7 @@ export class CommonFindController extends Disposable implements IEditorContribut
// overwritten in subclass
}
protected _start(opts: IFindStartOptions): void {
protected async _start(opts: IFindStartOptions): Promise<void> {
this.disposeModel();
if (!this._editor.hasModel()) {
@@ -279,7 +279,7 @@ export class CommonFindController extends Disposable implements IEditorContribut
}
if (!stateChanges.searchString && opts.seedSearchStringFromGlobalClipboard) {
let selectionSearchString = this.getGlobalBufferTerm();
let selectionSearchString = await this.getGlobalBufferTerm();
if (selectionSearchString) {
stateChanges.searchString = selectionSearchString;
}
@@ -308,8 +308,8 @@ export class CommonFindController extends Disposable implements IEditorContribut
}
}
public start(opts: IFindStartOptions): void {
this._start(opts);
public start(opts: IFindStartOptions): Promise<void> {
return this._start(opts);
}
public moveToNextMatch(): boolean {
@@ -353,24 +353,24 @@ export class CommonFindController extends Disposable implements IEditorContribut
return false;
}
public getGlobalBufferTerm(): string {
public async getGlobalBufferTerm(): Promise<string> {
if (this._editor.getOption(EditorOption.find).globalFindClipboard
&& this._clipboardService
&& this._editor.hasModel()
&& !this._editor.getModel().isTooLargeForSyncing()
) {
return this._clipboardService.readFindTextSync();
return this._clipboardService.readFindText();
}
return '';
}
public setGlobalBufferTerm(text: string) {
public async setGlobalBufferTerm(text: string) {
if (this._editor.getOption(EditorOption.find).globalFindClipboard
&& this._clipboardService
&& this._editor.hasModel()
&& !this._editor.getModel().isTooLargeForSyncing()
) {
this._clipboardService.writeFindTextSync(text);
await this._clipboardService.writeFindText(text);
}
}
}
@@ -396,7 +396,7 @@ export class FindController extends CommonFindController implements IFindControl
this._findOptionsWidget = null;
}
protected _start(opts: IFindStartOptions): void {
protected async _start(opts: IFindStartOptions): Promise<void> {
if (!this._widget) {
this._createFindWidget();
}
@@ -422,7 +422,7 @@ export class FindController extends CommonFindController implements IFindControl
opts.updateSearchScope = updateSearchScope;
super._start(opts);
await super._start(opts);
if (opts.shouldFocus === FindStartFocusAction.FocusReplaceInput) {
this._widget!.focusReplaceInput();
@@ -505,7 +505,7 @@ export class StartFindWithSelectionAction extends EditorAction {
});
}
public run(accessor: ServicesAccessor, editor: ICodeEditor): void {
public async run(accessor: ServicesAccessor, editor: ICodeEditor): Promise<void> {
let controller = CommonFindController.get(editor);
if (controller) {
controller.start({
@@ -518,7 +518,7 @@ export class StartFindWithSelectionAction extends EditorAction {
loop: editor.getOption(EditorOption.find).loop
});
controller.setGlobalBufferTerm(controller.getState().searchString);
return controller.setGlobalBufferTerm(controller.getState().searchString);
}
}
}

View File

@@ -262,6 +262,13 @@ export class FindModelBoundToEditorModel {
private _moveToPrevMatch(before: Position, isRecursed: boolean = false): void {
if (!this._state.canNavigateBack()) {
// we are beyond the first matched find result
// instead of doing nothing, we should refocus the first item
const nextMatchRange = this._decorations.matchAfterPosition(before);
if (nextMatchRange) {
this._setCurrentFindMatch(nextMatchRange);
}
return;
}
if (this._decorations.getCount() < MATCHES_LIMIT) {
@@ -350,6 +357,13 @@ export class FindModelBoundToEditorModel {
private _moveToNextMatch(after: Position): void {
if (!this._state.canNavigateForward()) {
// we are beyond the last matched find result
// instead of doing nothing, we should refocus the last item
const prevMatchRange = this._decorations.matchBeforePosition(after);
if (prevMatchRange) {
this._setCurrentFindMatch(prevMatchRange);
}
return;
}
if (this._decorations.getCount() < MATCHES_LIMIT) {

View File

@@ -52,7 +52,7 @@ export const findNextMatchIcon = registerIcon('find-next-match', Codicon.arrowDo
export interface IFindController {
replace(): void;
replaceAll(): void;
getGlobalBufferTerm(): string;
getGlobalBufferTerm(): Promise<string>;
}
const NLS_FIND_INPUT_LABEL = nls.localize('label.find', "Find");
@@ -224,9 +224,9 @@ export class FindWidget extends Widget implements IOverlayWidget, IVerticalSashL
this._updateToggleSelectionFindButton();
}
}));
this._register(this._codeEditor.onDidFocusEditorWidget(() => {
this._register(this._codeEditor.onDidFocusEditorWidget(async () => {
if (this._isVisible) {
let globalBufferTerm = this._controller.getGlobalBufferTerm();
let globalBufferTerm = await this._controller.getGlobalBufferTerm();
if (globalBufferTerm && globalBufferTerm !== this._state.searchString) {
this._state.change({ searchString: globalBufferTerm }, true);
this._findInput.select();

View File

@@ -39,8 +39,8 @@ export class TestFindController extends CommonFindController {
this.hasFocus = false;
}
protected _start(opts: IFindStartOptions): void {
super._start(opts);
protected async _start(opts: IFindStartOptions): Promise<void> {
await super._start(opts);
if (opts.shouldFocus !== FindStartFocusAction.NoFocusChange) {
this.hasFocus = true;

View File

@@ -70,7 +70,8 @@ suite('Multicursor selection', () => {
remove: (key) => undefined,
logStorage: () => undefined,
migrate: (toWorkspace) => Promise.resolve(undefined),
flush: () => undefined
flush: () => undefined,
isNew: () => true
} as IStorageService);
test('issue #8817: Cursor position changes when you cancel multicursor', () => {

View File

@@ -4,7 +4,7 @@
*--------------------------------------------------------------------------------------------*/
.monaco-editor .peekview-widget .head {
box-sizing: border-box;
box-sizing: border-box;
display: flex;
}
@@ -14,6 +14,7 @@
font-size: 13px;
margin-left: 20px;
cursor: pointer;
min-width: 0;
}
.monaco-editor .peekview-widget .head .peekview-title .dirname:not(:empty) {
@@ -25,6 +26,15 @@
white-space: nowrap;
}
.monaco-editor .peekview-widget .head .peekview-title .dirname {
white-space: nowrap;
}
.monaco-editor .peekview-widget .head .peekview-title .filename {
overflow: hidden;
text-overflow: ellipsis;
}
.monaco-editor .peekview-widget .head .peekview-title .meta:not(:empty)::before {
content: '-';
padding: 0 0.3em;

View File

@@ -167,7 +167,7 @@ suite('WordOperations', () => {
test('cursorWordStartLeft', () => {
// This is the behaviour observed in Visual Studio, please do not touch test
const EXPECTED = ['| |/* |Just |some |more |text |a|+= |3 |+|5|-|3 |+ |7 |*/| '].join('\n');
const EXPECTED = ['| |/* |Just |some |more |text |a|+= |3 |+|5|-|3 |+ |7 |*/ '].join('\n');
const [text,] = deserializePipePositions(EXPECTED);
const actualStops = testRepeatedActionAndExtractPositions(
text,

View File

@@ -115,9 +115,12 @@ export interface IGlobalEditorOptions {
wordBasedSuggestions?: boolean;
/**
* Controls whether the semanticHighlighting is shown for the languages that support it.
* Defaults to true.
* true: semanticHighlighting is enabled for all themes
* false: semanticHighlighting is disabled for all themes
* 'configuredByTheme': semanticHighlighting is controlled by the current color theme's semanticHighlighting setting.
* Defaults to 'byTheme'.
*/
'semanticHighlighting.enabled'?: boolean;
'semanticHighlighting.enabled'?: true | false | 'configuredByTheme';
/**
* Keep peek editors open even when double clicking their content or when hitting `Escape`.
* Defaults to false.

View File

@@ -31,14 +31,14 @@ var RECORDED_EVENTS = [];
var input = document.getElementById('input');
var blackListedProps = [
var blockedProperties = [
'currentTarget',
'path',
'srcElement',
'target',
'view'
];
blackListedProps = blackListedProps.concat([
blockedProperties = blockedProperties.concat([
'AT_TARGET',
'BLUR',
'BUBBLING_PHASE',
@@ -68,7 +68,7 @@ blackListedProps = blackListedProps.concat([
function toSerializable(e) {
var r = {};
for (var k in e) {
if (blackListedProps.indexOf(k) >= 0) {
if (blockedProperties.indexOf(k) >= 0) {
continue;
}
if (typeof e[k] === 'function') {
@@ -112,4 +112,4 @@ document.getElementById('stop').onclick = function() {
</script>
</body>
</html>
</html>

View File

@@ -781,4 +781,29 @@ suite('TextModelSearch', () => {
model.dispose();
});
test('issue #100134. Zero-length matches should properly step over surrogate pairs', () => {
// 1[Laptop]1 - there shoud be no matches inside of [Laptop] emoji
assertFindMatches('1\uD83D\uDCBB1', '()', true, false, null,
[
[1, 1, 1, 1],
[1, 2, 1, 2],
[1, 4, 1, 4],
[1, 5, 1, 5],
]
);
// 1[Hacker Cat]1 = 1[Cat Face][ZWJ][Laptop]1 - there shoud be matches between emoji and ZWJ
// there shoud be no matches inside of [Cat Face] and [Laptop] emoji
assertFindMatches('1\uD83D\uDC31\u200D\uD83D\uDCBB1', '()', true, false, null,
[
[1, 1, 1, 1],
[1, 2, 1, 2],
[1, 4, 1, 4],
[1, 5, 1, 5],
[1, 7, 1, 7],
[1, 8, 1, 8]
]
);
});
});

View File

@@ -104,4 +104,15 @@ suite('LanguageSelector', function () {
let value = score(selector, URI.parse('file:///C:/Users/zlhe/Desktop/test.interface.json'), 'json', true);
assert.equal(value, 10);
});
test('Document selector match - platform paths #99938', function () {
let selector = {
pattern: {
base: '/home/user/Desktop',
pattern: '*.json'
}
};
let value = score(selector, URI.file('/home/user/Desktop/test.json'), 'json', true);
assert.equal(value, 10);
});
});

View File

@@ -223,4 +223,11 @@ suite('Editor Modes - Link Computer', () => {
' https://foo.bar/[this is foo site] '
);
});
test('issue #100353: Link detection stops at (double-byte)', () => {
assertLink(
'aa http://tree-mark.chips.jp/レーズン&ベリーミックス aa',
' http://tree-mark.chips.jp/レーズン&ベリーミックス '
);
});
});