Update to VS Code 1.52.1

This commit is contained in:
Asher
2021-02-09 16:08:37 +00:00
1351 changed files with 56560 additions and 38990 deletions

View File

@@ -502,6 +502,16 @@ const editorConfiguration: IConfigurationNode = {
default: true,
description: nls.localize('wordBasedSuggestions', "Controls whether completions should be computed based on words in the document.")
},
'editor.wordBasedSuggestionsMode': {
enum: ['currentDocument', 'matchingDocuments', 'allDocuments'],
default: 'matchingDocuments',
enumDescriptions: [
nls.localize('wordBasedSuggestionsMode.currentDocument', 'Only suggest words from the active document.'),
nls.localize('wordBasedSuggestionsMode.matchingDocuments', 'Suggest words from all open documents of the same language.'),
nls.localize('wordBasedSuggestionsMode.allDocuments', 'Suggest words from all open documents.')
],
description: nls.localize('wordBasedSuggestionsMode', "Controls form what documents word based completions are computed.")
},
'editor.semanticHighlighting.enabled': {
enum: [true, false, 'configuredByTheme'],
enumDescriptions: [
@@ -546,6 +556,16 @@ const editorConfiguration: IConfigurationNode = {
type: 'boolean',
default: false,
description: nls.localize('codeLens', "Controls whether the editor shows CodeLens.")
},
'diffEditor.wordWrap': {
type: 'string',
enum: ['off', 'on', 'inherit'],
default: 'inherit',
markdownEnumDescriptions: [
nls.localize('wordWrap.off', "Lines will never wrap."),
nls.localize('wordWrap.on', "Lines will wrap at the viewport width."),
nls.localize('wordWrap.inherit', "Lines will wrap according to the `#editor.wordWrap#` setting."),
]
}
}
};

View File

@@ -144,9 +144,13 @@ export interface IEditorOptions {
*/
readOnly?: boolean;
/**
* Rename matching regions on type.
* Enable linked editing.
* Defaults to false.
*/
linkedEditing?: boolean;
/**
* deprecated, use linkedEditing instead
*/
renameOnType?: boolean;
/**
* Should the editor render validation decorations.
@@ -260,6 +264,14 @@ export interface IEditorOptions {
* Defaults to "off".
*/
wordWrap?: 'off' | 'on' | 'wordWrapColumn' | 'bounded';
/**
* Override the `wordWrap` setting.
*/
wordWrapOverride1?: 'off' | 'on' | 'inherit';
/**
* Override the `wordWrapOverride1` setting.
*/
wordWrapOverride2?: 'off' | 'on' | 'inherit';
/**
* Control the wrapping of the editor.
* When `wordWrap` = "off", the lines will never wrap.
@@ -269,11 +281,6 @@ export interface IEditorOptions {
* Defaults to 80.
*/
wordWrapColumn?: number;
/**
* Force word wrapping when the text appears to be of a minified/generated file.
* Defaults to true.
*/
wordWrapMinified?: boolean;
/**
* Control indentation of wrapped lines. Can be: 'none', 'same', 'indent' or 'deepIndent'.
* Defaults to 'same' in vscode and to 'none' in monaco-editor.
@@ -370,6 +377,10 @@ export interface IEditorOptions {
* Suggest options.
*/
suggest?: ISuggestOptions;
/**
* Smart select opptions;
*/
smartSelect?: ISmartSelectOptions;
/**
*
*/
@@ -416,6 +427,11 @@ export interface IEditorOptions {
* Defaults to advanced.
*/
autoIndent?: 'none' | 'keep' | 'brackets' | 'advanced' | 'full';
/**
* Emulate selection behaviour of tab characters when using spaces for indentation.
* This means selection will stick to tab stops.
*/
stickyTabStops?: boolean;
/**
* Enable format on type.
* Defaults to false.
@@ -491,6 +507,14 @@ export interface IEditorOptions {
* Defaults to true.
*/
codeLens?: boolean;
/**
* Code lens font family. Defaults to editor font family.
*/
codeLensFontFamily?: string;
/**
* Code lens font size. Default to 90% of the editor font size
*/
codeLensFontSize?: number;
/**
* Control the behavior and rendering of the code action lightbulb.
*/
@@ -644,15 +668,19 @@ export interface IDiffEditorOptions extends IEditorOptions {
*/
originalEditable?: boolean;
/**
* Original editor should be have code lens enabled?
* Should the diff editor enable code lens?
* Defaults to false.
*/
originalCodeLens?: boolean;
diffCodeLens?: boolean;
/**
* Modified editor should be have code lens enabled?
* Defaults to false.
* Is the diff editor inside another editor
* Defaults to false
*/
modifiedCodeLens?: boolean;
isInEmbeddedEditor?: boolean;
/**
* Control the wrapping of the diff editor.
*/
diffWordWrap?: 'off' | 'on' | 'inherit';
}
//#endregion
@@ -828,18 +856,21 @@ class SimpleEditorOption<K1 extends EditorOption, V> implements IEditorOption<K1
}
}
class EditorBooleanOption<K1 extends EditorOption> extends SimpleEditorOption<K1, boolean> {
public static boolean(value: any, defaultValue: boolean): boolean {
if (typeof value === 'undefined') {
return defaultValue;
}
if (value === 'false') {
// treat the string 'false' as false
return false;
}
return Boolean(value);
/**
* @internal
*/
export function boolean(value: any, defaultValue: boolean): boolean {
if (typeof value === 'undefined') {
return defaultValue;
}
if (value === 'false') {
// treat the string 'false' as false
return false;
}
return Boolean(value);
}
class EditorBooleanOption<K1 extends EditorOption> extends SimpleEditorOption<K1, boolean> {
constructor(id: K1, name: PossibleKeyName<boolean>, defaultValue: boolean, schema: IConfigurationPropertySchema | undefined = undefined) {
if (typeof schema !== 'undefined') {
@@ -850,7 +881,7 @@ class EditorBooleanOption<K1 extends EditorOption> extends SimpleEditorOption<K1
}
public validate(input: any): boolean {
return EditorBooleanOption.boolean(input, this.defaultValue);
return boolean(input, this.defaultValue);
}
}
@@ -950,17 +981,20 @@ class EditorStringOption<K1 extends EditorOption> extends SimpleEditorOption<K1,
}
}
class EditorStringEnumOption<K1 extends EditorOption, V extends string> extends SimpleEditorOption<K1, V> {
public static stringSet<T>(value: T | undefined, defaultValue: T, allowedValues: ReadonlyArray<T>): T {
if (typeof value !== 'string') {
return defaultValue;
}
if (allowedValues.indexOf(value) === -1) {
return defaultValue;
}
return value;
/**
* @internal
*/
export function stringSet<T>(value: T | undefined, defaultValue: T, allowedValues: ReadonlyArray<T>): T {
if (typeof value !== 'string') {
return defaultValue;
}
if (allowedValues.indexOf(value) === -1) {
return defaultValue;
}
return value;
}
class EditorStringEnumOption<K1 extends EditorOption, V extends string> extends SimpleEditorOption<K1, V> {
private readonly _allowedValues: ReadonlyArray<V>;
@@ -975,7 +1009,7 @@ class EditorStringEnumOption<K1 extends EditorOption, V extends string> extends
}
public validate(input: any): V {
return EditorStringEnumOption.stringSet<V>(input, this.defaultValue, this._allowedValues);
return stringSet<V>(input, this.defaultValue, this._allowedValues);
}
}
@@ -1113,8 +1147,8 @@ class EditorComments extends BaseEditorOption<EditorOption.comments, EditorComme
}
const input = _input as IEditorCommentsOptions;
return {
insertSpace: EditorBooleanOption.boolean(input.insertSpace, this.defaultValue.insertSpace),
ignoreEmptyLines: EditorBooleanOption.boolean(input.ignoreEmptyLines, this.defaultValue.ignoreEmptyLines),
insertSpace: boolean(input.insertSpace, this.defaultValue.insertSpace),
ignoreEmptyLines: boolean(input.ignoreEmptyLines, this.defaultValue.ignoreEmptyLines),
};
}
}
@@ -1375,14 +1409,14 @@ class EditorFind extends BaseEditorOption<EditorOption.find, EditorFindOptions>
}
const input = _input as IEditorFindOptions;
return {
cursorMoveOnType: EditorBooleanOption.boolean(input.cursorMoveOnType, this.defaultValue.cursorMoveOnType),
seedSearchStringFromSelection: EditorBooleanOption.boolean(input.seedSearchStringFromSelection, this.defaultValue.seedSearchStringFromSelection),
cursorMoveOnType: boolean(input.cursorMoveOnType, this.defaultValue.cursorMoveOnType),
seedSearchStringFromSelection: boolean(input.seedSearchStringFromSelection, this.defaultValue.seedSearchStringFromSelection),
autoFindInSelection: typeof _input.autoFindInSelection === 'boolean'
? (_input.autoFindInSelection ? 'always' : 'never')
: EditorStringEnumOption.stringSet<'never' | 'always' | 'multiline'>(input.autoFindInSelection, this.defaultValue.autoFindInSelection, ['never', 'always', 'multiline']),
globalFindClipboard: EditorBooleanOption.boolean(input.globalFindClipboard, this.defaultValue.globalFindClipboard),
addExtraSpaceOnTop: EditorBooleanOption.boolean(input.addExtraSpaceOnTop, this.defaultValue.addExtraSpaceOnTop),
loop: EditorBooleanOption.boolean(input.loop, this.defaultValue.loop),
: stringSet<'never' | 'always' | 'multiline'>(input.autoFindInSelection, this.defaultValue.autoFindInSelection, ['never', 'always', 'multiline']),
globalFindClipboard: boolean(input.globalFindClipboard, this.defaultValue.globalFindClipboard),
addExtraSpaceOnTop: boolean(input.addExtraSpaceOnTop, this.defaultValue.addExtraSpaceOnTop),
loop: boolean(input.loop, this.defaultValue.loop),
};
}
}
@@ -1406,14 +1440,14 @@ export class EditorFontLigatures extends BaseEditorOption<EditorOption.fontLigat
anyOf: [
{
type: 'boolean',
description: nls.localize('fontLigatures', "Enables/Disables font ligatures."),
description: nls.localize('fontLigatures', "Enables/Disables font ligatures ('calt' and 'liga' font features). Change this to a string for fine-grained control of the 'font-feature-settings' CSS property."),
},
{
type: 'string',
description: nls.localize('fontFeatureSettings', "Explicit font-feature-settings.")
description: nls.localize('fontFeatureSettings', "Explicit 'font-feature-settings' CSS property. A boolean can be passed instead if one only needs to turn on/off ligatures.")
}
],
description: nls.localize('fontLigaturesGeneral', "Configures font ligatures or font features."),
description: nls.localize('fontLigaturesGeneral', "Configures font ligatures or font features. Can be either a boolean to enable/disable ligatures or a string for the value of the CSS 'font-feature-settings' property."),
default: false
}
);
@@ -1644,12 +1678,12 @@ class EditorGoToLocation extends BaseEditorOption<EditorOption.gotoLocation, GoT
}
const input = _input as IGotoLocationOptions;
return {
multiple: EditorStringEnumOption.stringSet<GoToLocationValues>(input.multiple, this.defaultValue.multiple!, ['peek', 'gotoAndPeek', 'goto']),
multipleDefinitions: input.multipleDefinitions ?? EditorStringEnumOption.stringSet<GoToLocationValues>(input.multipleDefinitions, 'peek', ['peek', 'gotoAndPeek', 'goto']),
multipleTypeDefinitions: input.multipleTypeDefinitions ?? EditorStringEnumOption.stringSet<GoToLocationValues>(input.multipleTypeDefinitions, 'peek', ['peek', 'gotoAndPeek', 'goto']),
multipleDeclarations: input.multipleDeclarations ?? EditorStringEnumOption.stringSet<GoToLocationValues>(input.multipleDeclarations, 'peek', ['peek', 'gotoAndPeek', 'goto']),
multipleImplementations: input.multipleImplementations ?? EditorStringEnumOption.stringSet<GoToLocationValues>(input.multipleImplementations, 'peek', ['peek', 'gotoAndPeek', 'goto']),
multipleReferences: input.multipleReferences ?? EditorStringEnumOption.stringSet<GoToLocationValues>(input.multipleReferences, 'peek', ['peek', 'gotoAndPeek', 'goto']),
multiple: stringSet<GoToLocationValues>(input.multiple, this.defaultValue.multiple!, ['peek', 'gotoAndPeek', 'goto']),
multipleDefinitions: input.multipleDefinitions ?? stringSet<GoToLocationValues>(input.multipleDefinitions, 'peek', ['peek', 'gotoAndPeek', 'goto']),
multipleTypeDefinitions: input.multipleTypeDefinitions ?? stringSet<GoToLocationValues>(input.multipleTypeDefinitions, 'peek', ['peek', 'gotoAndPeek', 'goto']),
multipleDeclarations: input.multipleDeclarations ?? stringSet<GoToLocationValues>(input.multipleDeclarations, 'peek', ['peek', 'gotoAndPeek', 'goto']),
multipleImplementations: input.multipleImplementations ?? stringSet<GoToLocationValues>(input.multipleImplementations, 'peek', ['peek', 'gotoAndPeek', 'goto']),
multipleReferences: input.multipleReferences ?? stringSet<GoToLocationValues>(input.multipleReferences, 'peek', ['peek', 'gotoAndPeek', 'goto']),
alternativeDefinitionCommand: EditorStringOption.string(input.alternativeDefinitionCommand, this.defaultValue.alternativeDefinitionCommand),
alternativeTypeDefinitionCommand: EditorStringOption.string(input.alternativeTypeDefinitionCommand, this.defaultValue.alternativeTypeDefinitionCommand),
alternativeDeclarationCommand: EditorStringOption.string(input.alternativeDeclarationCommand, this.defaultValue.alternativeDeclarationCommand),
@@ -1722,9 +1756,9 @@ class EditorHover extends BaseEditorOption<EditorOption.hover, EditorHoverOption
}
const input = _input as IEditorHoverOptions;
return {
enabled: EditorBooleanOption.boolean(input.enabled, this.defaultValue.enabled),
enabled: boolean(input.enabled, this.defaultValue.enabled),
delay: EditorIntOption.clampedInt(input.delay, this.defaultValue.delay, 0, 10000),
sticky: EditorBooleanOption.boolean(input.sticky, this.defaultValue.sticky)
sticky: boolean(input.sticky, this.defaultValue.sticky)
};
}
}
@@ -1928,7 +1962,7 @@ export class EditorLayoutInfoComputer extends ComputedEditorOption<EditorOption.
EditorOption.glyphMargin, EditorOption.lineDecorationsWidth, EditorOption.folding,
EditorOption.minimap, EditorOption.scrollbar, EditorOption.lineNumbers,
EditorOption.lineNumbersMinChars, EditorOption.scrollBeyondLastLine,
EditorOption.wordWrap, EditorOption.wordWrapColumn, EditorOption.wordWrapMinified,
EditorOption.wordWrap, EditorOption.wordWrapColumn, EditorOption.wordWrapOverride1, EditorOption.wordWrapOverride2,
EditorOption.accessibilitySupport
]
);
@@ -2139,9 +2173,11 @@ export class EditorLayoutInfoComputer extends ComputedEditorOption<EditorOption.
const pixelRatio = env.pixelRatio;
const viewLineCount = env.viewLineCount;
const wordWrap = options.get(EditorOption.wordWrap);
const wordWrapOverride2 = options.get(EditorOption.wordWrapOverride2);
const wordWrapOverride1 = (wordWrapOverride2 === 'inherit' ? options.get(EditorOption.wordWrapOverride1) : wordWrapOverride2);
const wordWrap = (wordWrapOverride1 === 'inherit' ? options.get(EditorOption.wordWrap) : wordWrapOverride1);
const wordWrapColumn = options.get(EditorOption.wordWrapColumn);
const wordWrapMinified = options.get(EditorOption.wordWrapMinified);
const accessibilitySupport = options.get(EditorOption.accessibilitySupport);
const isDominatedByLongLines = env.isDominatedByLongLines;
@@ -2198,7 +2234,7 @@ export class EditorLayoutInfoComputer extends ComputedEditorOption<EditorOption.
// Never enable wrapping when a screen reader is attached
// because arrow down etc. will not move the cursor in the way
// a screen reader expects.
if (wordWrapMinified && isDominatedByLongLines) {
if (wordWrapOverride1 === 'inherit' && isDominatedByLongLines) {
// Force viewport width wrapping if model is dominated by long lines
isWordWrapMinified = true;
isViewportWrapping = true;
@@ -2321,7 +2357,7 @@ class EditorLightbulb extends BaseEditorOption<EditorOption.lightbulb, EditorLig
}
const input = _input as IEditorLightbulbOptions;
return {
enabled: EditorBooleanOption.boolean(input.enabled, this.defaultValue.enabled)
enabled: boolean(input.enabled, this.defaultValue.enabled)
};
}
}
@@ -2465,11 +2501,11 @@ class EditorMinimap extends BaseEditorOption<EditorOption.minimap, EditorMinimap
}
const input = _input as IEditorMinimapOptions;
return {
enabled: EditorBooleanOption.boolean(input.enabled, this.defaultValue.enabled),
size: EditorStringEnumOption.stringSet<'proportional' | 'fill' | 'fit'>(input.size, this.defaultValue.size, ['proportional', 'fill', 'fit']),
side: EditorStringEnumOption.stringSet<'right' | 'left'>(input.side, this.defaultValue.side, ['right', 'left']),
showSlider: EditorStringEnumOption.stringSet<'always' | 'mouseover'>(input.showSlider, this.defaultValue.showSlider, ['always', 'mouseover']),
renderCharacters: EditorBooleanOption.boolean(input.renderCharacters, this.defaultValue.renderCharacters),
enabled: boolean(input.enabled, this.defaultValue.enabled),
size: stringSet<'proportional' | 'fill' | 'fit'>(input.size, this.defaultValue.size, ['proportional', 'fill', 'fit']),
side: stringSet<'right' | 'left'>(input.side, this.defaultValue.side, ['right', 'left']),
showSlider: stringSet<'always' | 'mouseover'>(input.showSlider, this.defaultValue.showSlider, ['always', 'mouseover']),
renderCharacters: boolean(input.renderCharacters, this.defaultValue.renderCharacters),
scale: EditorIntOption.clampedInt(input.scale, 1, 1, 3),
maxColumn: EditorIntOption.clampedInt(input.maxColumn, this.defaultValue.maxColumn, 1, 10000),
};
@@ -2598,8 +2634,8 @@ class EditorParameterHints extends BaseEditorOption<EditorOption.parameterHints,
}
const input = _input as IEditorParameterHintOptions;
return {
enabled: EditorBooleanOption.boolean(input.enabled, this.defaultValue.enabled),
cycle: EditorBooleanOption.boolean(input.cycle, this.defaultValue.cycle)
enabled: boolean(input.enabled, this.defaultValue.enabled),
cycle: boolean(input.cycle, this.defaultValue.cycle)
};
}
}
@@ -2686,9 +2722,9 @@ class EditorQuickSuggestions extends BaseEditorOption<EditorOption.quickSuggesti
if (_input && typeof _input === 'object') {
const input = _input as IQuickSuggestionsOptions;
const opts = {
other: EditorBooleanOption.boolean(input.other, this.defaultValue.other),
comments: EditorBooleanOption.boolean(input.comments, this.defaultValue.comments),
strings: EditorBooleanOption.boolean(input.strings, this.defaultValue.strings),
other: boolean(input.other, this.defaultValue.other),
comments: boolean(input.comments, this.defaultValue.comments),
strings: boolean(input.strings, this.defaultValue.strings),
};
if (opts.other && opts.comments && opts.strings) {
return true; // all on
@@ -2916,6 +2952,11 @@ export interface IEditorScrollbarOptions {
* Defaults to `horizontalScrollbarSize`.
*/
horizontalSliderSize?: number;
/**
* Scroll gutter clicks move by page vs jump to position.
* Defaults to false.
*/
scrollByPage?: boolean;
}
export interface InternalEditorScrollbarOptions {
@@ -2931,6 +2972,7 @@ export interface InternalEditorScrollbarOptions {
readonly horizontalSliderSize: number;
readonly verticalScrollbarSize: number;
readonly verticalSliderSize: number;
readonly scrollByPage: boolean;
}
function _scrollbarVisibilityFromString(visibility: string | undefined, defaultValue: ScrollbarVisibility): ScrollbarVisibility {
@@ -2961,7 +3003,8 @@ class EditorScrollbar extends BaseEditorOption<EditorOption.scrollbar, InternalE
verticalScrollbarSize: 14,
verticalSliderSize: 14,
handleMouseWheel: true,
alwaysConsumeMouseWheel: true
alwaysConsumeMouseWheel: true,
scrollByPage: false
}
);
}
@@ -2977,15 +3020,16 @@ class EditorScrollbar extends BaseEditorOption<EditorOption.scrollbar, InternalE
arrowSize: EditorIntOption.clampedInt(input.arrowSize, this.defaultValue.arrowSize, 0, 1000),
vertical: _scrollbarVisibilityFromString(input.vertical, this.defaultValue.vertical),
horizontal: _scrollbarVisibilityFromString(input.horizontal, this.defaultValue.horizontal),
useShadows: EditorBooleanOption.boolean(input.useShadows, this.defaultValue.useShadows),
verticalHasArrows: EditorBooleanOption.boolean(input.verticalHasArrows, this.defaultValue.verticalHasArrows),
horizontalHasArrows: EditorBooleanOption.boolean(input.horizontalHasArrows, this.defaultValue.horizontalHasArrows),
handleMouseWheel: EditorBooleanOption.boolean(input.handleMouseWheel, this.defaultValue.handleMouseWheel),
alwaysConsumeMouseWheel: EditorBooleanOption.boolean(input.alwaysConsumeMouseWheel, this.defaultValue.alwaysConsumeMouseWheel),
useShadows: boolean(input.useShadows, this.defaultValue.useShadows),
verticalHasArrows: boolean(input.verticalHasArrows, this.defaultValue.verticalHasArrows),
horizontalHasArrows: boolean(input.horizontalHasArrows, this.defaultValue.horizontalHasArrows),
handleMouseWheel: boolean(input.handleMouseWheel, this.defaultValue.handleMouseWheel),
alwaysConsumeMouseWheel: boolean(input.alwaysConsumeMouseWheel, this.defaultValue.alwaysConsumeMouseWheel),
horizontalScrollbarSize: horizontalScrollbarSize,
horizontalSliderSize: EditorIntOption.clampedInt(input.horizontalSliderSize, horizontalScrollbarSize, 0, 1000),
verticalScrollbarSize: verticalScrollbarSize,
verticalSliderSize: EditorIntOption.clampedInt(input.verticalSliderSize, verticalScrollbarSize, 0, 1000),
scrollByPage: boolean(input.scrollByPage, this.defaultValue.scrollByPage),
};
}
}
@@ -3026,6 +3070,10 @@ export interface ISuggestOptions {
* Enable or disable the suggest status bar.
*/
showStatusBar?: boolean;
/**
* Show details inline with the label. Defaults to true.
*/
showInlineDetails?: boolean;
/**
* Show method-suggestions.
*/
@@ -3149,6 +3197,7 @@ class EditorSuggest extends BaseEditorOption<EditorOption.suggest, InternalSugge
shareSuggestSelections: false,
showIcons: true,
showStatusBar: false,
showInlineDetails: true,
showMethods: true,
showFunctions: true,
showConstructors: true,
@@ -3220,6 +3269,12 @@ class EditorSuggest extends BaseEditorOption<EditorOption.suggest, InternalSugge
default: defaults.showStatusBar,
description: nls.localize('suggest.showStatusBar', "Controls the visibility of the status bar at the bottom of the suggest widget.")
},
'editor.suggest.showInlineDetails': {
type: 'boolean',
default: defaults.showInlineDetails,
description: nls.localize('suggest.showInlineDetails', "Controls whether sugget details show inline with the label or only in the details widget")
},
'editor.suggest.maxVisibleSuggestions': {
type: 'number',
deprecationMessage: nls.localize('suggest.maxVisibleSuggestions.dep', "This setting is deprecated. The suggest widget can now be resized."),
@@ -3378,40 +3433,79 @@ class EditorSuggest extends BaseEditorOption<EditorOption.suggest, InternalSugge
}
const input = _input as ISuggestOptions;
return {
insertMode: EditorStringEnumOption.stringSet(input.insertMode, this.defaultValue.insertMode, ['insert', 'replace']),
filterGraceful: EditorBooleanOption.boolean(input.filterGraceful, this.defaultValue.filterGraceful),
snippetsPreventQuickSuggestions: EditorBooleanOption.boolean(input.snippetsPreventQuickSuggestions, this.defaultValue.filterGraceful),
localityBonus: EditorBooleanOption.boolean(input.localityBonus, this.defaultValue.localityBonus),
shareSuggestSelections: EditorBooleanOption.boolean(input.shareSuggestSelections, this.defaultValue.shareSuggestSelections),
showIcons: EditorBooleanOption.boolean(input.showIcons, this.defaultValue.showIcons),
showStatusBar: EditorBooleanOption.boolean(input.showStatusBar, this.defaultValue.showStatusBar),
showMethods: EditorBooleanOption.boolean(input.showMethods, this.defaultValue.showMethods),
showFunctions: EditorBooleanOption.boolean(input.showFunctions, this.defaultValue.showFunctions),
showConstructors: EditorBooleanOption.boolean(input.showConstructors, this.defaultValue.showConstructors),
showFields: EditorBooleanOption.boolean(input.showFields, this.defaultValue.showFields),
showVariables: EditorBooleanOption.boolean(input.showVariables, this.defaultValue.showVariables),
showClasses: EditorBooleanOption.boolean(input.showClasses, this.defaultValue.showClasses),
showStructs: EditorBooleanOption.boolean(input.showStructs, this.defaultValue.showStructs),
showInterfaces: EditorBooleanOption.boolean(input.showInterfaces, this.defaultValue.showInterfaces),
showModules: EditorBooleanOption.boolean(input.showModules, this.defaultValue.showModules),
showProperties: EditorBooleanOption.boolean(input.showProperties, this.defaultValue.showProperties),
showEvents: EditorBooleanOption.boolean(input.showEvents, this.defaultValue.showEvents),
showOperators: EditorBooleanOption.boolean(input.showOperators, this.defaultValue.showOperators),
showUnits: EditorBooleanOption.boolean(input.showUnits, this.defaultValue.showUnits),
showValues: EditorBooleanOption.boolean(input.showValues, this.defaultValue.showValues),
showConstants: EditorBooleanOption.boolean(input.showConstants, this.defaultValue.showConstants),
showEnums: EditorBooleanOption.boolean(input.showEnums, this.defaultValue.showEnums),
showEnumMembers: EditorBooleanOption.boolean(input.showEnumMembers, this.defaultValue.showEnumMembers),
showKeywords: EditorBooleanOption.boolean(input.showKeywords, this.defaultValue.showKeywords),
showWords: EditorBooleanOption.boolean(input.showWords, this.defaultValue.showWords),
showColors: EditorBooleanOption.boolean(input.showColors, this.defaultValue.showColors),
showFiles: EditorBooleanOption.boolean(input.showFiles, this.defaultValue.showFiles),
showReferences: EditorBooleanOption.boolean(input.showReferences, this.defaultValue.showReferences),
showFolders: EditorBooleanOption.boolean(input.showFolders, this.defaultValue.showFolders),
showTypeParameters: EditorBooleanOption.boolean(input.showTypeParameters, this.defaultValue.showTypeParameters),
showSnippets: EditorBooleanOption.boolean(input.showSnippets, this.defaultValue.showSnippets),
showUsers: EditorBooleanOption.boolean(input.showUsers, this.defaultValue.showUsers),
showIssues: EditorBooleanOption.boolean(input.showIssues, this.defaultValue.showIssues),
insertMode: stringSet(input.insertMode, this.defaultValue.insertMode, ['insert', 'replace']),
filterGraceful: boolean(input.filterGraceful, this.defaultValue.filterGraceful),
snippetsPreventQuickSuggestions: boolean(input.snippetsPreventQuickSuggestions, this.defaultValue.filterGraceful),
localityBonus: boolean(input.localityBonus, this.defaultValue.localityBonus),
shareSuggestSelections: boolean(input.shareSuggestSelections, this.defaultValue.shareSuggestSelections),
showIcons: boolean(input.showIcons, this.defaultValue.showIcons),
showStatusBar: boolean(input.showStatusBar, this.defaultValue.showStatusBar),
showInlineDetails: boolean(input.showInlineDetails, this.defaultValue.showInlineDetails),
showMethods: boolean(input.showMethods, this.defaultValue.showMethods),
showFunctions: boolean(input.showFunctions, this.defaultValue.showFunctions),
showConstructors: boolean(input.showConstructors, this.defaultValue.showConstructors),
showFields: boolean(input.showFields, this.defaultValue.showFields),
showVariables: boolean(input.showVariables, this.defaultValue.showVariables),
showClasses: boolean(input.showClasses, this.defaultValue.showClasses),
showStructs: boolean(input.showStructs, this.defaultValue.showStructs),
showInterfaces: boolean(input.showInterfaces, this.defaultValue.showInterfaces),
showModules: boolean(input.showModules, this.defaultValue.showModules),
showProperties: boolean(input.showProperties, this.defaultValue.showProperties),
showEvents: boolean(input.showEvents, this.defaultValue.showEvents),
showOperators: boolean(input.showOperators, this.defaultValue.showOperators),
showUnits: boolean(input.showUnits, this.defaultValue.showUnits),
showValues: boolean(input.showValues, this.defaultValue.showValues),
showConstants: boolean(input.showConstants, this.defaultValue.showConstants),
showEnums: boolean(input.showEnums, this.defaultValue.showEnums),
showEnumMembers: boolean(input.showEnumMembers, this.defaultValue.showEnumMembers),
showKeywords: boolean(input.showKeywords, this.defaultValue.showKeywords),
showWords: boolean(input.showWords, this.defaultValue.showWords),
showColors: boolean(input.showColors, this.defaultValue.showColors),
showFiles: boolean(input.showFiles, this.defaultValue.showFiles),
showReferences: boolean(input.showReferences, this.defaultValue.showReferences),
showFolders: boolean(input.showFolders, this.defaultValue.showFolders),
showTypeParameters: boolean(input.showTypeParameters, this.defaultValue.showTypeParameters),
showSnippets: boolean(input.showSnippets, this.defaultValue.showSnippets),
showUsers: boolean(input.showUsers, this.defaultValue.showUsers),
showIssues: boolean(input.showIssues, this.defaultValue.showIssues),
};
}
}
//#endregion
//#region smart select
export interface ISmartSelectOptions {
selectLeadingAndTrailingWhitespace?: boolean
}
export type SmartSelectOptions = Readonly<Required<ISmartSelectOptions>>;
class SmartSelect extends BaseEditorOption<EditorOption.smartSelect, SmartSelectOptions> {
constructor() {
super(
EditorOption.smartSelect, 'smartSelect',
{
selectLeadingAndTrailingWhitespace: true
},
{
'editor.smartSelect.selectLeadingAndTrailingWhitespace': {
description: nls.localize('selectLeadingAndTrailingWhitespace', "Whether leading and trailing whitespace should always be selected."),
default: true,
type: 'boolean'
}
}
);
}
public validate(input: any): Readonly<Required<ISmartSelectOptions>> {
if (!input || typeof input !== 'object') {
return this.defaultValue;
}
return {
selectLeadingAndTrailingWhitespace: boolean((input as ISmartSelectOptions).selectLeadingAndTrailingWhitespace, this.defaultValue.selectLeadingAndTrailingWhitespace)
};
}
}
@@ -3552,6 +3646,8 @@ export const enum EditorOption {
automaticLayout,
autoSurround,
codeLens,
codeLensFontFamily,
codeLensFontSize,
colorDecorators,
columnSelection,
comments,
@@ -3594,6 +3690,7 @@ export const enum EditorOption {
lineHeight,
lineNumbers,
lineNumbersMinChars,
linkedEditing,
links,
matchBrackets,
minimap,
@@ -3634,7 +3731,9 @@ export const enum EditorOption {
showFoldingControls,
showUnused,
snippetSuggestions,
smartSelect,
smoothScrolling,
stickyTabStops,
stopRenderingLineAfter,
suggest,
suggestFontSize,
@@ -3650,7 +3749,8 @@ export const enum EditorOption {
wordWrapBreakAfterCharacters,
wordWrapBreakBeforeCharacters,
wordWrapColumn,
wordWrapMinified,
wordWrapOverride1,
wordWrapOverride2,
wrappingIndent,
wrappingStrategy,
showDeprecated,
@@ -3776,10 +3876,25 @@ export const EditorOptions = {
description: nls.localize('autoSurround', "Controls whether the editor should automatically surround selections when typing quotes or brackets.")
}
)),
stickyTabStops: register(new EditorBooleanOption(
EditorOption.stickyTabStops, 'stickyTabStops', false,
{ description: nls.localize('stickyTabStops', "Emulate selection behaviour of tab characters when using spaces for indentation. Selection will stick to tab stops.") }
)),
codeLens: register(new EditorBooleanOption(
EditorOption.codeLens, 'codeLens', true,
{ description: nls.localize('codeLens', "Controls whether the editor shows CodeLens.") }
)),
codeLensFontFamily: register(new EditorStringOption(
EditorOption.codeLensFontFamily, 'codeLensFontFamily', '',
{ description: nls.localize('codeLensFontFamily', "Controls the font family for CodeLens.") }
)),
codeLensFontSize: register(new EditorIntOption(EditorOption.codeLensFontSize, 'codeLensFontSize', 0, 0, 100, {
type: 'number',
default: 0,
minimum: 0,
maximum: 100,
description: nls.localize('codeLensFontSize', "Controls the font size in pixels for CodeLens. When set to `0`, the 90% of `#editor.fontSize#` is used.")
})),
colorDecorators: register(new EditorBooleanOption(
EditorOption.colorDecorators, 'colorDecorators', true,
{ description: nls.localize('colorDecorators', "Controls whether the editor should render the inline color decorators and color picker.") }
@@ -3914,7 +4029,7 @@ export const EditorOptions = {
)),
hover: register(new EditorHover()),
inDiffEditor: register(new EditorBooleanOption(
EditorOption.inDiffEditor, 'inDiffEditor', false,
EditorOption.inDiffEditor, 'inDiffEditor', false
)),
letterSpacing: register(new EditorFloatOption(
EditorOption.letterSpacing, 'letterSpacing',
@@ -3929,6 +4044,10 @@ export const EditorOptions = {
EditorOption.lineNumbersMinChars, 'lineNumbersMinChars',
5, 1, 300
)),
linkedEditing: register(new EditorBooleanOption(
EditorOption.linkedEditing, 'linkedEditing', false,
{ description: nls.localize('linkedEditing', "Controls whether the editor has linked editing enabled. Depending on the language, related symbols, e.g. HTML tags, are updated while editing.") }
)),
links: register(new EditorBooleanOption(
EditorOption.links, 'links', true,
{ description: nls.localize('links', "Controls whether the editor should detect links and make them clickable.") }
@@ -4030,7 +4149,7 @@ export const EditorOptions = {
)),
renameOnType: register(new EditorBooleanOption(
EditorOption.renameOnType, 'renameOnType', false,
{ description: nls.localize('renameOnType', "Controls whether the editor auto renames on type.") }
{ description: nls.localize('renameOnType', "Controls whether the editor auto renames on type."), markdownDeprecationMessage: nls.localize('renameOnTypeDeprecate', "Deprecated, use `editor.linkedEditing` instead.") }
)),
renderControlCharacters: register(new EditorBooleanOption(
EditorOption.renderControlCharacters, 'renderControlCharacters', false,
@@ -4153,6 +4272,7 @@ export const EditorOptions = {
description: nls.localize('snippetSuggestions', "Controls whether snippets are shown with other suggestions and how they are sorted.")
}
)),
smartSelect: register(new SmartSelect()),
smoothScrolling: register(new EditorBooleanOption(
EditorOption.smoothScrolling, 'smoothScrolling', false,
{ description: nls.localize('smoothScrolling', "Controls whether the editor will scroll using an animation.") }
@@ -4170,7 +4290,7 @@ export const EditorOptions = {
suggestLineHeight: register(new EditorIntOption(
EditorOption.suggestLineHeight, 'suggestLineHeight',
0, 0, 1000,
{ markdownDescription: nls.localize('suggestLineHeight', "Line height for the suggest widget. When set to `0`, the value of `#editor.lineHeight#` is used.") }
{ markdownDescription: nls.localize('suggestLineHeight', "Line height for the suggest widget. When set to `0`, the value of `#editor.lineHeight#` is used. The minimum value is 8.") }
)),
suggestOnTriggerCharacters: register(new EditorBooleanOption(
EditorOption.suggestOnTriggerCharacters, 'suggestOnTriggerCharacters', true,
@@ -4279,8 +4399,15 @@ export const EditorOptions = {
}, "Controls the wrapping column of the editor when `#editor.wordWrap#` is `wordWrapColumn` or `bounded`.")
}
)),
wordWrapMinified: register(new EditorBooleanOption(
EditorOption.wordWrapMinified, 'wordWrapMinified', true,
wordWrapOverride1: register(new EditorStringEnumOption(
EditorOption.wordWrapOverride1, 'wordWrapOverride1',
'inherit' as 'off' | 'on' | 'inherit',
['off', 'on', 'inherit'] as const
)),
wordWrapOverride2: register(new EditorStringEnumOption(
EditorOption.wordWrapOverride2, 'wordWrapOverride2',
'inherit' as 'off' | 'on' | 'inherit',
['off', 'on', 'inherit'] as const
)),
wrappingIndent: register(new EditorEnumOption(
EditorOption.wrappingIndent, 'wrappingIndent',

View File

@@ -531,7 +531,7 @@ export class Cursor extends Disposable {
}
const closeChar = m[1];
const autoClosingPairsCandidates = this.context.cursorConfig.autoClosingPairsClose2.get(closeChar);
const autoClosingPairsCandidates = this.context.cursorConfig.autoClosingPairs.autoClosingPairsCloseSingleChar.get(closeChar);
if (!autoClosingPairsCandidates || autoClosingPairsCandidates.length !== 1) {
return null;
}

View File

@@ -0,0 +1,160 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { CharCode } from 'vs/base/common/charCode';
import { CursorColumns } from 'vs/editor/common/controller/cursorCommon';
export const enum Direction {
Left,
Right,
Nearest,
}
export class AtomicTabMoveOperations {
/**
* Get the visible column at the position. If we get to a non-whitespace character first
* or past the end of string then return -1.
*
* **Note** `position` and the return value are 0-based.
*/
public static whitespaceVisibleColumn(lineContent: string, position: number, tabSize: number): [number, number, number] {
const lineLength = lineContent.length;
let visibleColumn = 0;
let prevTabStopPosition = -1;
let prevTabStopVisibleColumn = -1;
for (let i = 0; i < lineLength; i++) {
if (i === position) {
return [prevTabStopPosition, prevTabStopVisibleColumn, visibleColumn];
}
if (visibleColumn % tabSize === 0) {
prevTabStopPosition = i;
prevTabStopVisibleColumn = visibleColumn;
}
const chCode = lineContent.charCodeAt(i);
switch (chCode) {
case CharCode.Space:
visibleColumn += 1;
break;
case CharCode.Tab:
// Skip to the next multiple of tabSize.
visibleColumn = CursorColumns.nextRenderTabStop(visibleColumn, tabSize);
break;
default:
return [-1, -1, -1];
}
}
if (position === lineLength) {
return [prevTabStopPosition, prevTabStopVisibleColumn, visibleColumn];
}
return [-1, -1, -1];
}
/**
* Return the position that should result from a move left, right or to the
* nearest tab, if atomic tabs are enabled. Left and right are used for the
* arrow key movements, nearest is used for mouse selection. It returns
* -1 if atomic tabs are not relevant and you should fall back to normal
* behaviour.
*
* **Note**: `position` and the return value are 0-based.
*/
public static atomicPosition(lineContent: string, position: number, tabSize: number, direction: Direction): number {
const lineLength = lineContent.length;
// Get the 0-based visible column corresponding to the position, or return
// -1 if it is not in the initial whitespace.
const [prevTabStopPosition, prevTabStopVisibleColumn, visibleColumn] = AtomicTabMoveOperations.whitespaceVisibleColumn(lineContent, position, tabSize);
if (visibleColumn === -1) {
return -1;
}
// Is the output left or right of the current position. The case for nearest
// where it is the same as the current position is handled in the switch.
let left: boolean;
switch (direction) {
case Direction.Left:
left = true;
break;
case Direction.Right:
left = false;
break;
case Direction.Nearest:
// The code below assumes the output position is either left or right
// of the input position. If it is the same, return immediately.
if (visibleColumn % tabSize === 0) {
return position;
}
// Go to the nearest indentation.
left = visibleColumn % tabSize <= (tabSize / 2);
break;
}
// If going left, we can just use the info about the last tab stop position and
// last tab stop visible column that we computed in the first walk over the whitespace.
if (left) {
if (prevTabStopPosition === -1) {
return -1;
}
// If the direction is left, we need to keep scanning right to ensure
// that targetVisibleColumn + tabSize is before non-whitespace.
// This is so that when we press left at the end of a partial
// indentation it only goes one character. For example ' foo' with
// tabSize 4, should jump from position 6 to position 5, not 4.
let currentVisibleColumn = prevTabStopVisibleColumn;
for (let i = prevTabStopPosition; i < lineLength; ++i) {
if (currentVisibleColumn === prevTabStopVisibleColumn + tabSize) {
// It is a full indentation.
return prevTabStopPosition;
}
const chCode = lineContent.charCodeAt(i);
switch (chCode) {
case CharCode.Space:
currentVisibleColumn += 1;
break;
case CharCode.Tab:
currentVisibleColumn = CursorColumns.nextRenderTabStop(currentVisibleColumn, tabSize);
break;
default:
return -1;
}
}
if (currentVisibleColumn === prevTabStopVisibleColumn + tabSize) {
return prevTabStopPosition;
}
// It must have been a partial indentation.
return -1;
}
// We are going right.
const targetVisibleColumn = CursorColumns.nextRenderTabStop(visibleColumn, tabSize);
// We can just continue from where whitespaceVisibleColumn got to.
let currentVisibleColumn = visibleColumn;
for (let i = position; i < lineLength; i++) {
if (currentVisibleColumn === targetVisibleColumn) {
return i;
}
const chCode = lineContent.charCodeAt(i);
switch (chCode) {
case CharCode.Space:
currentVisibleColumn += 1;
break;
case CharCode.Tab:
currentVisibleColumn = CursorColumns.nextRenderTabStop(currentVisibleColumn, tabSize);
break;
default:
return -1;
}
}
// This condition handles when the target column is at the end of the line.
if (currentVisibleColumn === targetVisibleColumn) {
return lineLength;
}
return -1;
}
}

View File

@@ -14,7 +14,7 @@ import { ICommand, IConfiguration } from 'vs/editor/common/editorCommon';
import { ITextModel, TextModelResolvedOptions } from 'vs/editor/common/model';
import { TextModel } from 'vs/editor/common/model/textModel';
import { LanguageIdentifier } from 'vs/editor/common/modes';
import { IAutoClosingPair, StandardAutoClosingPairConditional } from 'vs/editor/common/modes/languageConfiguration';
import { AutoClosingPairs, IAutoClosingPair } from 'vs/editor/common/modes/languageConfiguration';
import { LanguageConfigurationRegistry } from 'vs/editor/common/modes/languageConfigurationRegistry';
import { ICoordinatesConverter } from 'vs/editor/common/viewModel/viewModel';
import { Constants } from 'vs/base/common/uint';
@@ -62,6 +62,7 @@ export class CursorConfiguration {
public readonly tabSize: number;
public readonly indentSize: number;
public readonly insertSpaces: boolean;
public readonly stickyTabStops: boolean;
public readonly pageSize: number;
public readonly lineHeight: number;
public readonly useTabStops: boolean;
@@ -75,8 +76,7 @@ export class CursorConfiguration {
public readonly autoClosingOvertype: EditorAutoClosingOvertypeStrategy;
public readonly autoSurround: EditorAutoSurroundStrategy;
public readonly autoIndent: EditorAutoIndentStrategy;
public readonly autoClosingPairsOpen2: Map<string, StandardAutoClosingPairConditional[]>;
public readonly autoClosingPairsClose2: Map<string, StandardAutoClosingPairConditional[]>;
public readonly autoClosingPairs: AutoClosingPairs;
public readonly surroundingPairs: CharacterMap;
public readonly shouldAutoCloseBefore: { quote: (ch: string) => boolean, bracket: (ch: string) => boolean };
@@ -114,6 +114,7 @@ export class CursorConfiguration {
this.tabSize = modelOptions.tabSize;
this.indentSize = modelOptions.indentSize;
this.insertSpaces = modelOptions.insertSpaces;
this.stickyTabStops = options.get(EditorOption.stickyTabStops);
this.lineHeight = options.get(EditorOption.lineHeight);
this.pageSize = Math.max(1, Math.floor(layoutInfo.height / this.lineHeight) - 2);
this.useTabStops = options.get(EditorOption.useTabStops);
@@ -136,9 +137,7 @@ export class CursorConfiguration {
bracket: CursorConfiguration._getShouldAutoClose(languageIdentifier, this.autoClosingBrackets)
};
const autoClosingPairs = LanguageConfigurationRegistry.getAutoClosingPairs(languageIdentifier.id);
this.autoClosingPairsOpen2 = autoClosingPairs.autoClosingPairsOpen;
this.autoClosingPairsClose2 = autoClosingPairs.autoClosingPairsClose;
this.autoClosingPairs = LanguageConfigurationRegistry.getAutoClosingPairs(languageIdentifier.id);
let surroundingPairs = CursorConfiguration._getSurroundingPairs(languageIdentifier);
if (surroundingPairs) {
@@ -557,14 +556,14 @@ export class CursorColumns {
}
/**
* ATTENTION: This works with 0-based columns (as oposed to the regular 1-based columns)
* ATTENTION: This works with 0-based columns (as opposed to the regular 1-based columns)
*/
public static prevRenderTabStop(column: number, tabSize: number): number {
return column - 1 - (column - 1) % tabSize;
}
/**
* ATTENTION: This works with 0-based columns (as oposed to the regular 1-based columns)
* ATTENTION: This works with 0-based columns (as opposed to the regular 1-based columns)
*/
public static prevIndentTabStop(column: number, indentSize: number): number {
return column - 1 - (column - 1) % indentSize;

View File

@@ -122,7 +122,7 @@ export class DeleteOperations {
public static deleteLeft(prevEditOperationType: EditOperationType, config: CursorConfiguration, model: ICursorSimpleModel, selections: Selection[]): [boolean, Array<ICommand | null>] {
if (this.isAutoClosingPairDelete(config.autoClosingBrackets, config.autoClosingQuotes, config.autoClosingPairsOpen2, model, selections)) {
if (this.isAutoClosingPairDelete(config.autoClosingBrackets, config.autoClosingQuotes, config.autoClosingPairs.autoClosingPairsOpenByEnd, model, selections)) {
return this._runAutoClosingPairDelete(config, model, selections);
}

View File

@@ -412,7 +412,11 @@ export class CursorMoveCommands {
const skipWrappingPointStop = hasMultipleCursors || !cursor.viewState.hasSelection();
let newViewState = MoveOperations.moveLeft(viewModel.cursorConfig, viewModel, cursor.viewState, inSelectionMode, noOfColumns);
if (skipWrappingPointStop && noOfColumns === 1 && newViewState.position.lineNumber !== cursor.viewState.position.lineNumber) {
if (skipWrappingPointStop
&& noOfColumns === 1
&& cursor.viewState.position.column === viewModel.getLineMinColumn(cursor.viewState.position.lineNumber)
&& newViewState.position.lineNumber !== cursor.viewState.position.lineNumber
) {
// moved over to the previous view line
const newViewModelPosition = viewModel.coordinatesConverter.convertViewPositionToModelPosition(newViewState.position);
if (newViewModelPosition.lineNumber === cursor.modelState.position.lineNumber) {
@@ -445,7 +449,11 @@ export class CursorMoveCommands {
const skipWrappingPointStop = hasMultipleCursors || !cursor.viewState.hasSelection();
let newViewState = MoveOperations.moveRight(viewModel.cursorConfig, viewModel, cursor.viewState, inSelectionMode, noOfColumns);
if (skipWrappingPointStop && noOfColumns === 1 && newViewState.position.lineNumber !== cursor.viewState.position.lineNumber) {
if (skipWrappingPointStop
&& noOfColumns === 1
&& cursor.viewState.position.column === viewModel.getLineMaxColumn(cursor.viewState.position.lineNumber)
&& newViewState.position.lineNumber !== cursor.viewState.position.lineNumber
) {
// moved over to the next view line
const newViewModelPosition = viewModel.coordinatesConverter.convertViewPositionToModelPosition(newViewState.position);
if (newViewModelPosition.lineNumber === cursor.modelState.position.lineNumber) {

View File

@@ -8,6 +8,7 @@ import { Position } from 'vs/editor/common/core/position';
import { Range } from 'vs/editor/common/core/range';
import * as strings from 'vs/base/common/strings';
import { Constants } from 'vs/base/common/uint';
import { AtomicTabMoveOperations, Direction } from 'vs/editor/common/controller/cursorAtomicMoveOperations';
export class CursorPosition {
_cursorPositionBrand: void;
@@ -35,8 +36,20 @@ export class MoveOperations {
return new Position(lineNumber, column);
}
public static leftPositionAtomicSoftTabs(model: ICursorSimpleModel, lineNumber: number, column: number, tabSize: number): Position {
const minColumn = model.getLineMinColumn(lineNumber);
const lineContent = model.getLineContent(lineNumber);
const newPosition = AtomicTabMoveOperations.atomicPosition(lineContent, column - minColumn, tabSize, Direction.Left);
if (newPosition === -1) {
return this.leftPosition(model, lineNumber, column);
}
return new Position(lineNumber, minColumn + newPosition);
}
public static left(config: CursorConfiguration, model: ICursorSimpleModel, lineNumber: number, column: number): CursorPosition {
const pos = MoveOperations.leftPosition(model, lineNumber, column);
const pos = config.stickyTabStops
? MoveOperations.leftPositionAtomicSoftTabs(model, lineNumber, column, config.tabSize)
: MoveOperations.leftPosition(model, lineNumber, column);
return new CursorPosition(pos.lineNumber, pos.column, 0);
}
@@ -67,8 +80,20 @@ export class MoveOperations {
return new Position(lineNumber, column);
}
public static rightPositionAtomicSoftTabs(model: ICursorSimpleModel, lineNumber: number, column: number, tabSize: number, indentSize: number): Position {
const minColumn = model.getLineMinColumn(lineNumber);
const lineContent = model.getLineContent(lineNumber);
const newPosition = AtomicTabMoveOperations.atomicPosition(lineContent, column - minColumn, tabSize, Direction.Right);
if (newPosition === -1) {
return this.rightPosition(model, lineNumber, column);
}
return new Position(lineNumber, minColumn + newPosition);
}
public static right(config: CursorConfiguration, model: ICursorSimpleModel, lineNumber: number, column: number): CursorPosition {
const pos = MoveOperations.rightPosition(model, lineNumber, column);
const pos = config.stickyTabStops
? MoveOperations.rightPositionAtomicSoftTabs(model, lineNumber, column, config.tabSize, config.indentSize)
: MoveOperations.rightPosition(model, lineNumber, column);
return new CursorPosition(pos.lineNumber, pos.column, 0);
}

View File

@@ -128,7 +128,7 @@ export class TypeOperations {
if (text.charCodeAt(text.length - 1) === CharCode.CarriageReturn) {
text = text.substr(0, text.length - 1);
}
let lines = text.split(/\r\n|\r|\n/);
let lines = strings.splitLines(text);
if (lines.length === selections.length) {
return lines;
}
@@ -439,7 +439,7 @@ export class TypeOperations {
return false;
}
if (!config.autoClosingPairsClose2.has(ch)) {
if (!config.autoClosingPairs.autoClosingPairsCloseSingleChar.has(ch)) {
return false;
}
@@ -498,31 +498,20 @@ export class TypeOperations {
});
}
private static _autoClosingPairIsSymmetric(autoClosingPair: StandardAutoClosingPairConditional): boolean {
const { open, close } = autoClosingPair;
return (open.indexOf(close) >= 0 || close.indexOf(open) >= 0);
}
private static _isBeforeClosingBrace(config: CursorConfiguration, lineAfter: string) {
// If the start of lineAfter can be interpretted as both a starting or ending brace, default to returning false
const nextChar = lineAfter.charAt(0);
const potentialStartingBraces = config.autoClosingPairs.autoClosingPairsOpenByStart.get(nextChar) || [];
const potentialClosingBraces = config.autoClosingPairs.autoClosingPairsCloseByStart.get(nextChar) || [];
private static _isBeforeClosingBrace(config: CursorConfiguration, autoClosingPair: StandardAutoClosingPairConditional, characterAfter: string) {
const otherAutoClosingPairs = config.autoClosingPairsClose2.get(characterAfter);
if (!otherAutoClosingPairs) {
return false;
}
const isBeforeStartingBrace = potentialStartingBraces.some(x => lineAfter.startsWith(x.open));
const isBeforeClosingBrace = potentialClosingBraces.some(x => lineAfter.startsWith(x.close));
const thisBraceIsSymmetric = TypeOperations._autoClosingPairIsSymmetric(autoClosingPair);
for (const otherAutoClosingPair of otherAutoClosingPairs) {
const otherBraceIsSymmetric = TypeOperations._autoClosingPairIsSymmetric(otherAutoClosingPair);
if (!thisBraceIsSymmetric && otherBraceIsSymmetric) {
continue;
}
return true;
}
return false;
return !isBeforeStartingBrace && isBeforeClosingBrace;
}
private static _findAutoClosingPairOpen(config: CursorConfiguration, model: ITextModel, positions: Position[], ch: string): StandardAutoClosingPairConditional | null {
const autoClosingPairCandidates = config.autoClosingPairsOpen2.get(ch);
const autoClosingPairCandidates = config.autoClosingPairs.autoClosingPairsOpenByEnd.get(ch);
if (!autoClosingPairCandidates) {
return null;
}
@@ -548,7 +537,29 @@ export class TypeOperations {
return autoClosingPair;
}
private static _isAutoClosingOpenCharType(config: CursorConfiguration, model: ITextModel, selections: Selection[], ch: string, insertOpenCharacter: boolean): StandardAutoClosingPairConditional | null {
private static _findSubAutoClosingPairClose(config: CursorConfiguration, autoClosingPair: StandardAutoClosingPairConditional): string {
if (autoClosingPair.open.length <= 1) {
return '';
}
const lastChar = autoClosingPair.close.charAt(autoClosingPair.close.length - 1);
// get candidates with the same last character as close
const subPairCandidates = config.autoClosingPairs.autoClosingPairsCloseByEnd.get(lastChar) || [];
let subPairMatch: StandardAutoClosingPairConditional | null = null;
for (const x of subPairCandidates) {
if (x.open !== autoClosingPair.open && autoClosingPair.open.includes(x.open) && autoClosingPair.close.endsWith(x.close)) {
if (!subPairMatch || x.open.length > subPairMatch.open.length) {
subPairMatch = x;
}
}
}
if (subPairMatch) {
return subPairMatch.close;
} else {
return '';
}
}
private static _getAutoClosingPairClose(config: CursorConfiguration, model: ITextModel, selections: Selection[], ch: string, insertOpenCharacter: boolean): string | null {
const chIsQuote = isQuote(ch);
const autoCloseConfig = chIsQuote ? config.autoClosingQuotes : config.autoClosingBrackets;
if (autoCloseConfig === 'never') {
@@ -560,6 +571,9 @@ export class TypeOperations {
return null;
}
const subAutoClosingPairClose = this._findSubAutoClosingPairClose(config, autoClosingPair);
let isSubAutoClosingPairPresent = true;
const shouldAutoCloseBefore = chIsQuote ? config.shouldAutoCloseBefore.quote : config.shouldAutoCloseBefore.bracket;
for (let i = 0, len = selections.length; i < len; i++) {
@@ -570,11 +584,16 @@ export class TypeOperations {
const position = selection.getPosition();
const lineText = model.getLineContent(position.lineNumber);
const lineAfter = lineText.substring(position.column - 1);
// Only consider auto closing the pair if a space follows or if another autoclosed pair follows
if (!lineAfter.startsWith(subAutoClosingPairClose)) {
isSubAutoClosingPairPresent = false;
}
// Only consider auto closing the pair if an allowed character follows or if another autoclosed pair closing brace follows
if (lineText.length > position.column - 1) {
const characterAfter = lineText.charAt(position.column - 1);
const isBeforeCloseBrace = TypeOperations._isBeforeClosingBrace(config, autoClosingPair, characterAfter);
const isBeforeCloseBrace = TypeOperations._isBeforeClosingBrace(config, lineAfter);
if (!isBeforeCloseBrace && !shouldAutoCloseBefore(characterAfter)) {
return null;
@@ -612,14 +631,18 @@ export class TypeOperations {
}
}
return autoClosingPair;
if (isSubAutoClosingPairPresent) {
return autoClosingPair.close.substring(0, autoClosingPair.close.length - subAutoClosingPairClose.length);
} else {
return autoClosingPair.close;
}
}
private static _runAutoClosingOpenCharType(prevEditOperationType: EditOperationType, config: CursorConfiguration, model: ITextModel, selections: Selection[], ch: string, insertOpenCharacter: boolean, autoClosingPair: StandardAutoClosingPairConditional): EditOperationResult {
private static _runAutoClosingOpenCharType(prevEditOperationType: EditOperationType, config: CursorConfiguration, model: ITextModel, selections: Selection[], ch: string, insertOpenCharacter: boolean, autoClosingPairClose: string): EditOperationResult {
let commands: ICommand[] = [];
for (let i = 0, len = selections.length; i < len; i++) {
const selection = selections[i];
commands[i] = new TypeWithAutoClosingCommand(selection, ch, insertOpenCharacter, autoClosingPair.close);
commands[i] = new TypeWithAutoClosingCommand(selection, ch, insertOpenCharacter, autoClosingPairClose);
}
return new EditOperationResult(EditOperationType.Typing, commands, {
shouldPushStackElementBefore: true,
@@ -794,9 +817,9 @@ export class TypeOperations {
});
}
const autoClosingPairOpenCharType = this._isAutoClosingOpenCharType(config, model, selections, ch, false);
if (autoClosingPairOpenCharType) {
return this._runAutoClosingOpenCharType(prevEditOperationType, config, model, selections, ch, false, autoClosingPairOpenCharType);
const autoClosingPairClose = this._getAutoClosingPairClose(config, model, selections, ch, false);
if (autoClosingPairClose !== null) {
return this._runAutoClosingOpenCharType(prevEditOperationType, config, model, selections, ch, false, autoClosingPairClose);
}
return null;
@@ -838,9 +861,9 @@ export class TypeOperations {
}
if (!isDoingComposition) {
const autoClosingPairOpenCharType = this._isAutoClosingOpenCharType(config, model, selections, ch, true);
if (autoClosingPairOpenCharType) {
return this._runAutoClosingOpenCharType(prevEditOperationType, config, model, selections, ch, true, autoClosingPairOpenCharType);
const autoClosingPairClose = this._getAutoClosingPairClose(config, model, selections, ch, true);
if (autoClosingPairClose) {
return this._runAutoClosingOpenCharType(prevEditOperationType, config, model, selections, ch, true, autoClosingPairClose);
}
}

View File

@@ -384,7 +384,7 @@ export class WordOperations {
return selection;
}
if (DeleteOperations.isAutoClosingPairDelete(ctx.autoClosingBrackets, ctx.autoClosingQuotes, ctx.autoClosingPairs.autoClosingPairsOpen, ctx.model, [ctx.selection])) {
if (DeleteOperations.isAutoClosingPairDelete(ctx.autoClosingBrackets, ctx.autoClosingQuotes, ctx.autoClosingPairs.autoClosingPairsOpenByEnd, ctx.model, [ctx.selection])) {
const position = ctx.selection.getPosition();
return new Range(position.lineNumber, position.column - 1, position.lineNumber, position.column + 1);
}
@@ -438,6 +438,122 @@ export class WordOperations {
return new Range(lineNumber, column, position.lineNumber, position.column);
}
public static deleteInsideWord(wordSeparators: WordCharacterClassifier, model: ITextModel, selection: Selection): Range {
if (!selection.isEmpty()) {
return selection;
}
const position = new Position(selection.positionLineNumber, selection.positionColumn);
let r = this._deleteInsideWordWhitespace(model, position);
if (r) {
return r;
}
return this._deleteInsideWordDetermineDeleteRange(wordSeparators, model, position);
}
private static _charAtIsWhitespace(str: string, index: number): boolean {
const charCode = str.charCodeAt(index);
return (charCode === CharCode.Space || charCode === CharCode.Tab);
}
private static _deleteInsideWordWhitespace(model: ICursorSimpleModel, position: Position): Range | null {
const lineContent = model.getLineContent(position.lineNumber);
const lineContentLength = lineContent.length;
if (lineContentLength === 0) {
// empty line
return null;
}
let leftIndex = Math.max(position.column - 2, 0);
if (!this._charAtIsWhitespace(lineContent, leftIndex)) {
// touches a non-whitespace character to the left
return null;
}
let rightIndex = Math.min(position.column - 1, lineContentLength - 1);
if (!this._charAtIsWhitespace(lineContent, rightIndex)) {
// touches a non-whitespace character to the right
return null;
}
// walk over whitespace to the left
while (leftIndex > 0 && this._charAtIsWhitespace(lineContent, leftIndex - 1)) {
leftIndex--;
}
// walk over whitespace to the right
while (rightIndex + 1 < lineContentLength && this._charAtIsWhitespace(lineContent, rightIndex + 1)) {
rightIndex++;
}
return new Range(position.lineNumber, leftIndex + 1, position.lineNumber, rightIndex + 2);
}
private static _deleteInsideWordDetermineDeleteRange(wordSeparators: WordCharacterClassifier, model: ICursorSimpleModel, position: Position): Range {
const lineContent = model.getLineContent(position.lineNumber);
const lineLength = lineContent.length;
if (lineLength === 0) {
// empty line
if (position.lineNumber > 1) {
return new Range(position.lineNumber - 1, model.getLineMaxColumn(position.lineNumber - 1), position.lineNumber, 1);
} else {
if (position.lineNumber < model.getLineCount()) {
return new Range(position.lineNumber, 1, position.lineNumber + 1, 1);
} else {
// empty model
return new Range(position.lineNumber, 1, position.lineNumber, 1);
}
}
}
const touchesWord = (word: IFindWordResult) => {
return (word.start + 1 <= position.column && position.column <= word.end + 1);
};
const createRangeWithPosition = (startColumn: number, endColumn: number) => {
startColumn = Math.min(startColumn, position.column);
endColumn = Math.max(endColumn, position.column);
return new Range(position.lineNumber, startColumn, position.lineNumber, endColumn);
};
const deleteWordAndAdjacentWhitespace = (word: IFindWordResult) => {
let startColumn = word.start + 1;
let endColumn = word.end + 1;
let expandedToTheRight = false;
while (endColumn - 1 < lineLength && this._charAtIsWhitespace(lineContent, endColumn - 1)) {
expandedToTheRight = true;
endColumn++;
}
if (!expandedToTheRight) {
while (startColumn > 1 && this._charAtIsWhitespace(lineContent, startColumn - 2)) {
startColumn--;
}
}
return createRangeWithPosition(startColumn, endColumn);
};
const prevWordOnLine = WordOperations._findPreviousWordOnLine(wordSeparators, model, position);
if (prevWordOnLine && touchesWord(prevWordOnLine)) {
return deleteWordAndAdjacentWhitespace(prevWordOnLine);
}
const nextWordOnLine = WordOperations._findNextWordOnLine(wordSeparators, model, position);
if (nextWordOnLine && touchesWord(nextWordOnLine)) {
return deleteWordAndAdjacentWhitespace(nextWordOnLine);
}
if (prevWordOnLine && nextWordOnLine) {
return createRangeWithPosition(prevWordOnLine.end + 1, nextWordOnLine.start + 1);
}
if (prevWordOnLine) {
return createRangeWithPosition(prevWordOnLine.start + 1, prevWordOnLine.end + 1);
}
if (nextWordOnLine) {
return createRangeWithPosition(nextWordOnLine.start + 1, nextWordOnLine.end + 1);
}
return createRangeWithPosition(1, lineLength + 1);
}
public static _deleteWordPartLeft(model: ICursorSimpleModel, selection: Selection): Range {
if (!selection.isEmpty()) {
return selection;

View File

@@ -24,6 +24,7 @@ export namespace EditorContextKeys {
export const textInputFocus = new RawContextKey<boolean>('textInputFocus', false);
export const readOnly = new RawContextKey<boolean>('editorReadonly', false);
export const inDiffEditor = new RawContextKey<boolean>('inDiffEditor', false);
export const columnSelection = new RawContextKey<boolean>('editorColumnSelection', false);
export const writable = readOnly.toNegated();
export const hasNonEmptySelection = new RawContextKey<boolean>('editorHasSelection', false);

View File

@@ -695,6 +695,11 @@ export interface ITextModel {
*/
getEOL(): string;
/**
* Get the end of line sequence predominantly used in the text buffer.
*/
getEndOfLineSequence(): EndOfLineSequence;
/**
* Get the minimum legal column for line at `lineNumber`
*/
@@ -850,7 +855,12 @@ export interface ITextModel {
/**
* @internal
*/
hasSemanticTokens(): boolean;
hasCompleteSemanticTokens(): boolean;
/**
* @internal
*/
hasSomeSemanticTokens(): boolean;
/**
* Flush all tokenization state.
@@ -1089,12 +1099,17 @@ export interface ITextModel {
detectIndentation(defaultInsertSpaces: boolean, defaultTabSize: number): void;
/**
* Push a stack element onto the undo stack. This acts as an undo/redo point.
* The idea is to use `pushEditOperations` to edit the model and then to
* `pushStackElement` to create an undo/redo stop point.
* Close the current undo-redo element.
* This offers a way to create an undo/redo stop point.
*/
pushStackElement(): void;
/**
* Open the current undo-redo element.
* This offers a way to remove the current undo/redo stop point.
*/
popStackElement(): void;
/**
* Push edit operations, basically editing the model. This is the preferred way
* of editing the model. The edit operations will land on the undo stack.
@@ -1138,7 +1153,7 @@ export interface ITextModel {
_applyRedo(changes: TextChange[], eol: EndOfLineSequence, resultingAlternativeVersionId: number, resultingSelection: Selection[] | null): void;
/**
* Undo edit operations until the first previous stop point created by `pushStackElement`.
* Undo edit operations until the previous undo/redo point.
* The inverse edit operations will be pushed on the redo stack.
* @internal
*/
@@ -1151,7 +1166,7 @@ export interface ITextModel {
canUndo(): boolean;
/**
* Redo edit operations until the next stop point created by `pushStackElement`.
* Redo edit operations until the next undo/redo point.
* The inverse edit operations will be pushed on the undo stack.
* @internal
*/

View File

@@ -199,6 +199,12 @@ export class SingleModelEditStackElement implements IResourceUndoRedoElement {
}
}
public open(): void {
if (!(this._data instanceof SingleModelEditStackData)) {
this._data = SingleModelEditStackData.deserialize(this._data);
}
}
public undo(): void {
if (URI.isUri(this.model)) {
// don't have a model
@@ -315,6 +321,10 @@ export class MultiModelEditStackElement implements IWorkspaceUndoRedoElement {
this._isOpen = false;
}
public open(): void {
// cannot reopen
}
public undo(): void {
this._isOpen = false;
@@ -386,6 +396,13 @@ export class EditStack {
}
}
public popStackElement(): void {
const lastElement = this._undoRedoService.getLastElement(this._model.uri);
if (isEditStackElement(lastElement)) {
lastElement.open();
}
}
public clear(): void {
this._undoRedoService.removeElements(this._model.uri);
}

View File

@@ -3,6 +3,7 @@
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { splitLines } from 'vs/base/common/strings';
import { URI } from 'vs/base/common/uri';
import { Position } from 'vs/editor/common/core/position';
import { IRange } from 'vs/editor/common/core/range';
@@ -131,7 +132,7 @@ export class MirrorTextModel {
// Nothing to insert
return;
}
let insertLines = insertText.split(/\r\n|\r|\n/);
let insertLines = splitLines(insertText);
if (insertLines.length === 1) {
// Inserting text on one line
this._setLineText(position.lineNumber - 1,

View File

@@ -12,7 +12,7 @@ import { PieceTreeBase, StringBuffer } from 'vs/editor/common/model/pieceTreeTex
import { SearchData } from 'vs/editor/common/model/textModelSearch';
import { countEOL, StringEOL } from 'vs/editor/common/model/tokensStore';
import { TextChange } from 'vs/editor/common/model/textChange';
import { IDisposable } from 'vs/base/common/lifecycle';
import { Disposable } from 'vs/base/common/lifecycle';
export interface IValidatedEditOperation {
sortIndex: number;
@@ -32,26 +32,24 @@ export interface IReverseSingleEditOperation extends IValidEditOperation {
sortIndex: number;
}
export class PieceTreeTextBuffer implements ITextBuffer, IDisposable {
private readonly _pieceTree: PieceTreeBase;
export class PieceTreeTextBuffer extends Disposable implements ITextBuffer {
private _pieceTree: PieceTreeBase;
private readonly _BOM: string;
private _mightContainRTL: boolean;
private _mightContainUnusualLineTerminators: boolean;
private _mightContainNonBasicASCII: boolean;
private readonly _onDidChangeContent: Emitter<void> = new Emitter<void>();
private readonly _onDidChangeContent: Emitter<void> = this._register(new Emitter<void>());
public readonly onDidChangeContent: Event<void> = this._onDidChangeContent.event;
constructor(chunks: StringBuffer[], BOM: string, eol: '\r\n' | '\n', containsRTL: boolean, containsUnusualLineTerminators: boolean, isBasicASCII: boolean, eolNormalized: boolean) {
super();
this._BOM = BOM;
this._mightContainNonBasicASCII = !isBasicASCII;
this._mightContainRTL = containsRTL;
this._mightContainUnusualLineTerminators = containsUnusualLineTerminators;
this._pieceTree = new PieceTreeBase(chunks, eol, eolNormalized);
}
dispose(): void {
this._onDidChangeContent.dispose();
}
// #region TextBuffer
public equals(other: ITextBuffer): boolean {

View File

@@ -387,6 +387,9 @@ export class TextModel extends Disposable implements model.ITextModel {
this._isDisposed = true;
super.dispose();
this._isDisposing = false;
// Manually release reference to previous text buffer to avoid large leaks
// in case someone leaks a TextModel reference
this._buffer = createTextBuffer('', this._options.defaultEOL);
}
private _assertNotDisposed(): void {
@@ -830,6 +833,15 @@ export class TextModel extends Disposable implements model.ITextModel {
return this._buffer.getEOL();
}
public getEndOfLineSequence(): model.EndOfLineSequence {
this._assertNotDisposed();
return (
this._buffer.getEOL() === '\n'
? model.EndOfLineSequence.LF
: model.EndOfLineSequence.CRLF
);
}
public getLineMinColumn(lineNumber: number): number {
this._assertNotDisposed();
return 1;
@@ -1213,6 +1225,10 @@ export class TextModel extends Disposable implements model.ITextModel {
this._commandManager.pushStackElement();
}
public popStackElement(): void {
this._commandManager.popStackElement();
}
public pushEOL(eol: model.EndOfLineSequence): void {
const currentEOL = (this.getEOL() === '\n' ? model.EndOfLineSequence.LF : model.EndOfLineSequence.CRLF);
if (currentEOL === eol) {
@@ -1868,12 +1884,16 @@ export class TextModel extends Disposable implements model.ITextModel {
});
}
public hasSemanticTokens(): boolean {
public hasCompleteSemanticTokens(): boolean {
return this._tokens2.isComplete();
}
public hasSomeSemanticTokens(): boolean {
return !this._tokens2.isEmpty();
}
public setPartialSemanticTokens(range: Range, tokens: MultilineTokens2[]): void {
if (this.hasSemanticTokens()) {
if (this.hasCompleteSemanticTokens()) {
return;
}
const changedRange = this._tokens2.setPartial(range, tokens);

View File

@@ -884,6 +884,10 @@ export class TokensStore2 {
this._isComplete = false;
}
public isEmpty(): boolean {
return (this._pieces.length === 0);
}
public set(pieces: MultilineTokens2[] | null, isComplete: boolean): void {
this._pieces = pieces || [];
this._isComplete = isComplete;

View File

@@ -19,7 +19,7 @@ import { TokenizationRegistryImpl } from 'vs/editor/common/modes/tokenizationReg
import { ExtensionIdentifier } from 'vs/platform/extensions/common/extensions';
import { IMarkerData } from 'vs/platform/markers/common/markers';
import { iconRegistry, Codicon } from 'vs/base/common/codicons';
import { ThemeIcon } from 'vs/platform/theme/common/themeService';
/**
* Open ended enum at runtime
* @internal
@@ -819,17 +819,32 @@ export interface DocumentHighlightProvider {
}
/**
* The rename provider interface defines the contract between extensions and
* the live-rename feature.
* The linked editing range provider interface defines the contract between extensions and
* the linked editing feature.
*/
export interface OnTypeRenameProvider {
wordPattern?: RegExp;
export interface LinkedEditingRangeProvider {
/**
* Provide a list of ranges that can be live-renamed together.
* Provide a list of ranges that can be edited together.
*/
provideOnTypeRenameRanges(model: model.ITextModel, position: Position, token: CancellationToken): ProviderResult<{ ranges: IRange[]; wordPattern?: RegExp; }>;
provideLinkedEditingRanges(model: model.ITextModel, position: Position, token: CancellationToken): ProviderResult<LinkedEditingRanges>;
}
/**
* Represents a list of ranges that can be edited together along with a word pattern to describe valid contents.
*/
export interface LinkedEditingRanges {
/**
* A list of ranges that can be edited together. The ranges must have
* identical length and text content. The ranges cannot overlap
*/
ranges: IRange[];
/**
* An optional word pattern that describes valid contents for the given ranges.
* If no pattern is provided, the language configuration's word pattern will be used.
*/
wordPattern?: RegExp;
}
/**
@@ -1359,7 +1374,10 @@ export interface WorkspaceEditMetadata {
needsConfirmation: boolean;
label: string;
description?: string;
iconPath?: { id: string } | URI | { light: URI, dark: URI };
/**
* @internal
*/
iconPath?: ThemeIcon | URI | { light: URI, dark: URI };
}
export interface WorkspaceFileEditOptions {
@@ -1367,6 +1385,10 @@ export interface WorkspaceFileEditOptions {
ignoreIfNotExists?: boolean;
ignoreIfExists?: boolean;
recursive?: boolean;
copy?: boolean;
folder?: boolean;
skipTrashBin?: boolean;
maxSize?: number;
}
export interface WorkspaceFileEdit {
@@ -1715,7 +1737,7 @@ export const DocumentHighlightProviderRegistry = new LanguageFeatureRegistry<Doc
/**
* @internal
*/
export const OnTypeRenameProviderRegistry = new LanguageFeatureRegistry<OnTypeRenameProvider>();
export const LinkedEditingRangeProviderRegistry = new LanguageFeatureRegistry<LinkedEditingRangeProvider>();
/**
* @internal

View File

@@ -294,17 +294,32 @@ export class StandardAutoClosingPairConditional {
* @internal
*/
export class AutoClosingPairs {
// it is useful to be able to get pairs using either end of open and close
public readonly autoClosingPairsOpen: Map<string, StandardAutoClosingPairConditional[]>;
public readonly autoClosingPairsClose: Map<string, StandardAutoClosingPairConditional[]>;
/** Key is first character of open */
public readonly autoClosingPairsOpenByStart: Map<string, StandardAutoClosingPairConditional[]>;
/** Key is last character of open */
public readonly autoClosingPairsOpenByEnd: Map<string, StandardAutoClosingPairConditional[]>;
/** Key is first character of close */
public readonly autoClosingPairsCloseByStart: Map<string, StandardAutoClosingPairConditional[]>;
/** Key is last character of close */
public readonly autoClosingPairsCloseByEnd: Map<string, StandardAutoClosingPairConditional[]>;
/** Key is close. Only has pairs that are a single character */
public readonly autoClosingPairsCloseSingleChar: Map<string, StandardAutoClosingPairConditional[]>;
constructor(autoClosingPairs: StandardAutoClosingPairConditional[]) {
this.autoClosingPairsOpen = new Map<string, StandardAutoClosingPairConditional[]>();
this.autoClosingPairsClose = new Map<string, StandardAutoClosingPairConditional[]>();
this.autoClosingPairsOpenByStart = new Map<string, StandardAutoClosingPairConditional[]>();
this.autoClosingPairsOpenByEnd = new Map<string, StandardAutoClosingPairConditional[]>();
this.autoClosingPairsCloseByStart = new Map<string, StandardAutoClosingPairConditional[]>();
this.autoClosingPairsCloseByEnd = new Map<string, StandardAutoClosingPairConditional[]>();
this.autoClosingPairsCloseSingleChar = new Map<string, StandardAutoClosingPairConditional[]>();
for (const pair of autoClosingPairs) {
appendEntry(this.autoClosingPairsOpen, pair.open.charAt(pair.open.length - 1), pair);
if (pair.close.length === 1) {
appendEntry(this.autoClosingPairsClose, pair.close, pair);
appendEntry(this.autoClosingPairsOpenByStart, pair.open.charAt(0), pair);
appendEntry(this.autoClosingPairsOpenByEnd, pair.open.charAt(pair.open.length - 1), pair);
appendEntry(this.autoClosingPairsCloseByStart, pair.close.charAt(0), pair);
appendEntry(this.autoClosingPairsCloseByEnd, pair.close.charAt(pair.close.length - 1), pair);
if (pair.close.length === 1 && pair.open.length === 1) {
appendEntry(this.autoClosingPairsCloseSingleChar, pair.close, pair);
}
}
}

View File

@@ -622,6 +622,12 @@ export class LanguageConfigurationRegistryImpl {
return null;
}
const scopedLineTokens = this.getScopedLineTokens(model, range.startLineNumber, range.startColumn);
if (scopedLineTokens.firstCharOffset) {
// this line has mixed languages and indentation rules will not work
return null;
}
const indentRulesSupport = this.getIndentRulesSupport(scopedLineTokens.languageId);
if (!indentRulesSupport) {
return null;

View File

@@ -12,6 +12,14 @@ export const enum IndentConsts {
UNINDENT_MASK = 0b00001000,
}
function resetGlobalRegex(reg: RegExp) {
if (reg.global) {
reg.lastIndex = 0;
}
return true;
}
export class IndentRulesSupport {
private readonly _indentationRules: IndentationRule;
@@ -22,7 +30,7 @@ export class IndentRulesSupport {
public shouldIncrease(text: string): boolean {
if (this._indentationRules) {
if (this._indentationRules.increaseIndentPattern && this._indentationRules.increaseIndentPattern.test(text)) {
if (this._indentationRules.increaseIndentPattern && resetGlobalRegex(this._indentationRules.increaseIndentPattern) && this._indentationRules.increaseIndentPattern.test(text)) {
return true;
}
// if (this._indentationRules.indentNextLinePattern && this._indentationRules.indentNextLinePattern.test(text)) {
@@ -33,14 +41,14 @@ export class IndentRulesSupport {
}
public shouldDecrease(text: string): boolean {
if (this._indentationRules && this._indentationRules.decreaseIndentPattern && this._indentationRules.decreaseIndentPattern.test(text)) {
if (this._indentationRules && this._indentationRules.decreaseIndentPattern && resetGlobalRegex(this._indentationRules.decreaseIndentPattern) && this._indentationRules.decreaseIndentPattern.test(text)) {
return true;
}
return false;
}
public shouldIndentNextLine(text: string): boolean {
if (this._indentationRules && this._indentationRules.indentNextLinePattern && this._indentationRules.indentNextLinePattern.test(text)) {
if (this._indentationRules && this._indentationRules.indentNextLinePattern && resetGlobalRegex(this._indentationRules.indentNextLinePattern) && this._indentationRules.indentNextLinePattern.test(text)) {
return true;
}
@@ -49,7 +57,7 @@ export class IndentRulesSupport {
public shouldIgnore(text: string): boolean {
// the text matches `unIndentedLinePattern`
if (this._indentationRules && this._indentationRules.unIndentedLinePattern && this._indentationRules.unIndentedLinePattern.test(text)) {
if (this._indentationRules && this._indentationRules.unIndentedLinePattern && resetGlobalRegex(this._indentationRules.unIndentedLinePattern) && this._indentationRules.unIndentedLinePattern.test(text)) {
return true;
}

View File

@@ -101,7 +101,7 @@ export function tokenizeLineToHTML(text: string, viewLineTokens: IViewLineTokens
function _tokenizeToString(text: string, tokenizationSupport: IReducedTokenizationSupport): string {
let result = `<div class="monaco-tokenized-source">`;
let lines = text.split(/\r\n|\r|\n/);
let lines = strings.splitLines(text);
let currentState = tokenizationSupport.getInitialState();
for (let i = 0, len = lines.length; i < len; i++) {
let line = lines[i];

View File

@@ -530,36 +530,30 @@ export class EditorSimpleWorker implements IRequestHandler, IDisposable {
private static readonly _suggestionsLimit = 10000;
public async textualSuggest(modelUrl: string, position: IPosition, wordDef: string, wordDefFlags: string): Promise<{ words: string[], duration: number } | null> {
const model = this._getModel(modelUrl);
if (!model) {
return null;
}
public async textualSuggest(modelUrls: string[], leadingWord: string | undefined, wordDef: string, wordDefFlags: string): Promise<{ words: string[], duration: number } | null> {
const sw = new StopWatch(true);
const words: string[] = [];
const seen = new Set<string>();
const wordDefRegExp = new RegExp(wordDef, wordDefFlags);
const seen = new Set<string>();
const wordAt = model.getWordAtPosition(position, wordDefRegExp);
if (wordAt) {
seen.add(model.getValueInRange(wordAt));
}
for (let word of model.words(wordDefRegExp)) {
if (seen.has(word)) {
outer: for (let url of modelUrls) {
const model = this._getModel(url);
if (!model) {
continue;
}
seen.add(word);
if (!isNaN(Number(word))) {
continue;
}
words.push(word);
if (seen.size > EditorSimpleWorker._suggestionsLimit) {
break;
for (let word of model.words(wordDefRegExp)) {
if (word === leadingWord || !isNaN(Number(word))) {
continue;
}
seen.add(word);
if (seen.size > EditorSimpleWorker._suggestionsLimit) {
break outer;
}
}
}
return { words, duration: sw.elapsed() };
return { words: Array.from(seen), duration: sw.elapsed() };
}

View File

@@ -3,12 +3,12 @@
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { IntervalTimer } from 'vs/base/common/async';
import { IntervalTimer, timeout } from 'vs/base/common/async';
import { Disposable, IDisposable, dispose, toDisposable, DisposableStore } from 'vs/base/common/lifecycle';
import { URI } from 'vs/base/common/uri';
import { SimpleWorkerClient, logOnceWebWorkerWarning, IWorkerClient } from 'vs/base/common/worker/simpleWorker';
import { DefaultWorkerFactory } from 'vs/base/worker/defaultWorkerFactory';
import { IPosition, Position } from 'vs/editor/common/core/position';
import { Position } from 'vs/editor/common/core/position';
import { IRange, Range } from 'vs/editor/common/core/range';
import { IChange } from 'vs/editor/common/editorCommon';
import { ITextModel } from 'vs/editor/common/model';
@@ -105,7 +105,7 @@ export class EditorWorkerServiceImpl extends Disposable implements IEditorWorker
const sw = StopWatch.create(true);
const result = this._workerManager.withWorker().then(client => client.computeMoreMinimalEdits(resource, edits));
result.finally(() => this._logService.trace('FORMAT#computeMoreMinimalEdits', resource.toString(true), sw.elapsed()));
return result;
return Promise.race([result, timeout(1000).then(() => edits)]);
} else {
return Promise.resolve(undefined);
@@ -148,20 +148,47 @@ class WordBasedCompletionItemProvider implements modes.CompletionItemProvider {
}
async provideCompletionItems(model: ITextModel, position: Position): Promise<modes.CompletionList | undefined> {
const { wordBasedSuggestions } = this._configurationService.getValue<{ wordBasedSuggestions?: boolean }>(model.uri, position, 'editor');
if (!wordBasedSuggestions) {
type WordBasedSuggestionsConfig = {
wordBasedSuggestions?: boolean,
wordBasedSuggestionsMode?: 'currentDocument' | 'matchingDocuments' | 'allDocuments'
};
const config = this._configurationService.getValue<WordBasedSuggestionsConfig>(model.uri, position, 'editor');
if (!config.wordBasedSuggestions) {
return undefined;
}
if (!canSyncModel(this._modelService, model.uri)) {
return undefined; // File too large
const models: URI[] = [];
if (config.wordBasedSuggestionsMode === 'currentDocument') {
// only current file and only if not too large
if (canSyncModel(this._modelService, model.uri)) {
models.push(model.uri);
}
} else {
// either all files or files of same language
for (const candidate of this._modelService.getModels()) {
if (!canSyncModel(this._modelService, candidate.uri)) {
continue;
}
if (candidate === model) {
models.unshift(candidate.uri);
} else if (config.wordBasedSuggestionsMode === 'allDocuments' || candidate.getLanguageIdentifier().id === model.getLanguageIdentifier().id) {
models.push(candidate.uri);
}
}
}
if (models.length === 0) {
return undefined; // File too large, no other files
}
const wordDefRegExp = LanguageConfigurationRegistry.getWordDefinition(model.getLanguageIdentifier().id);
const word = model.getWordAtPosition(position);
const replace = !word ? Range.fromPositions(position) : new Range(position.lineNumber, word.startColumn, position.lineNumber, word.endColumn);
const insert = replace.setEndPosition(position.lineNumber, position.column);
const client = await this._workerManager.withWorker();
const data = await client.textualSuggest(model.uri, position);
const data = await client.textualSuggest(models, word?.word, wordDefRegExp);
if (!data) {
return undefined;
}
@@ -463,17 +490,11 @@ export class EditorWorkerClient extends Disposable {
});
}
public textualSuggest(resource: URI, position: IPosition): Promise<{ words: string[], duration: number } | null> {
return this._withSyncedResources([resource]).then(proxy => {
let model = this._modelService.getModel(resource);
if (!model) {
return null;
}
let wordDefRegExp = LanguageConfigurationRegistry.getWordDefinition(model.getLanguageIdentifier().id);
let wordDef = wordDefRegExp.source;
let wordDefFlags = regExpFlags(wordDefRegExp);
return proxy.textualSuggest(resource.toString(), position, wordDef, wordDefFlags);
});
public async textualSuggest(resources: URI[], leadingWord: string | undefined, wordDefRegExp: RegExp): Promise<{ words: string[], duration: number } | null> {
const proxy = await this._withSyncedResources(resources);
const wordDef = wordDefRegExp.source;
const wordDefFlags = regExpFlags(wordDefRegExp);
return proxy.textualSuggest(resources.map(r => r.toString()), leadingWord, wordDef, wordDefFlags);
}
computeWordRanges(resource: URI, range: IRange): Promise<{ [word: string]: IRange[] } | null> {

View File

@@ -93,6 +93,6 @@ export function detectModeId(modelService: IModelService, modeService: IModeServ
return modeService.getModeIdByFilepathOrFirstLine(resource);
}
export function cssEscape(val: string): string {
return val.replace(/\s/g, '\\$&'); // make sure to not introduce CSS classes from files that contain whitespace
export function cssEscape(str: string): string {
return str.replace(/[\11\12\14\15\40]/g, '/'); // HTML class names can not contain certain whitespace characters, use / instead, which doesn't exist in file names.
}

View File

@@ -790,6 +790,10 @@ class ModelSemanticColoring extends Disposable {
}
const provider = this._getSemanticColoringProvider();
if (!provider) {
if (this._currentDocumentResponse) {
// there are semantic tokens set
this._model.setSemanticTokens(null, false);
}
return;
}
this._currentDocumentRequestCancellationTokenSource = new CancellationTokenSource();

View File

@@ -179,113 +179,119 @@ export enum EditorOption {
automaticLayout = 9,
autoSurround = 10,
codeLens = 11,
colorDecorators = 12,
columnSelection = 13,
comments = 14,
contextmenu = 15,
copyWithSyntaxHighlighting = 16,
cursorBlinking = 17,
cursorSmoothCaretAnimation = 18,
cursorStyle = 19,
cursorSurroundingLines = 20,
cursorSurroundingLinesStyle = 21,
cursorWidth = 22,
disableLayerHinting = 23,
disableMonospaceOptimizations = 24,
dragAndDrop = 25,
emptySelectionClipboard = 26,
extraEditorClassName = 27,
fastScrollSensitivity = 28,
find = 29,
fixedOverflowWidgets = 30,
folding = 31,
foldingStrategy = 32,
foldingHighlight = 33,
unfoldOnClickAfterEndOfLine = 34,
fontFamily = 35,
fontInfo = 36,
fontLigatures = 37,
fontSize = 38,
fontWeight = 39,
formatOnPaste = 40,
formatOnType = 41,
glyphMargin = 42,
gotoLocation = 43,
hideCursorInOverviewRuler = 44,
highlightActiveIndentGuide = 45,
hover = 46,
inDiffEditor = 47,
letterSpacing = 48,
lightbulb = 49,
lineDecorationsWidth = 50,
lineHeight = 51,
lineNumbers = 52,
lineNumbersMinChars = 53,
links = 54,
matchBrackets = 55,
minimap = 56,
mouseStyle = 57,
mouseWheelScrollSensitivity = 58,
mouseWheelZoom = 59,
multiCursorMergeOverlapping = 60,
multiCursorModifier = 61,
multiCursorPaste = 62,
occurrencesHighlight = 63,
overviewRulerBorder = 64,
overviewRulerLanes = 65,
padding = 66,
parameterHints = 67,
peekWidgetDefaultFocus = 68,
definitionLinkOpensInPeek = 69,
quickSuggestions = 70,
quickSuggestionsDelay = 71,
readOnly = 72,
renameOnType = 73,
renderControlCharacters = 74,
renderIndentGuides = 75,
renderFinalNewline = 76,
renderLineHighlight = 77,
renderLineHighlightOnlyWhenFocus = 78,
renderValidationDecorations = 79,
renderWhitespace = 80,
revealHorizontalRightPadding = 81,
roundedSelection = 82,
rulers = 83,
scrollbar = 84,
scrollBeyondLastColumn = 85,
scrollBeyondLastLine = 86,
scrollPredominantAxis = 87,
selectionClipboard = 88,
selectionHighlight = 89,
selectOnLineNumbers = 90,
showFoldingControls = 91,
showUnused = 92,
snippetSuggestions = 93,
smoothScrolling = 94,
stopRenderingLineAfter = 95,
suggest = 96,
suggestFontSize = 97,
suggestLineHeight = 98,
suggestOnTriggerCharacters = 99,
suggestSelection = 100,
tabCompletion = 101,
tabIndex = 102,
unusualLineTerminators = 103,
useTabStops = 104,
wordSeparators = 105,
wordWrap = 106,
wordWrapBreakAfterCharacters = 107,
wordWrapBreakBeforeCharacters = 108,
wordWrapColumn = 109,
wordWrapMinified = 110,
wrappingIndent = 111,
wrappingStrategy = 112,
showDeprecated = 113,
editorClassName = 114,
pixelRatio = 115,
tabFocusMode = 116,
layoutInfo = 117,
wrappingInfo = 118
codeLensFontFamily = 12,
codeLensFontSize = 13,
colorDecorators = 14,
columnSelection = 15,
comments = 16,
contextmenu = 17,
copyWithSyntaxHighlighting = 18,
cursorBlinking = 19,
cursorSmoothCaretAnimation = 20,
cursorStyle = 21,
cursorSurroundingLines = 22,
cursorSurroundingLinesStyle = 23,
cursorWidth = 24,
disableLayerHinting = 25,
disableMonospaceOptimizations = 26,
dragAndDrop = 27,
emptySelectionClipboard = 28,
extraEditorClassName = 29,
fastScrollSensitivity = 30,
find = 31,
fixedOverflowWidgets = 32,
folding = 33,
foldingStrategy = 34,
foldingHighlight = 35,
unfoldOnClickAfterEndOfLine = 36,
fontFamily = 37,
fontInfo = 38,
fontLigatures = 39,
fontSize = 40,
fontWeight = 41,
formatOnPaste = 42,
formatOnType = 43,
glyphMargin = 44,
gotoLocation = 45,
hideCursorInOverviewRuler = 46,
highlightActiveIndentGuide = 47,
hover = 48,
inDiffEditor = 49,
letterSpacing = 50,
lightbulb = 51,
lineDecorationsWidth = 52,
lineHeight = 53,
lineNumbers = 54,
lineNumbersMinChars = 55,
linkedEditing = 56,
links = 57,
matchBrackets = 58,
minimap = 59,
mouseStyle = 60,
mouseWheelScrollSensitivity = 61,
mouseWheelZoom = 62,
multiCursorMergeOverlapping = 63,
multiCursorModifier = 64,
multiCursorPaste = 65,
occurrencesHighlight = 66,
overviewRulerBorder = 67,
overviewRulerLanes = 68,
padding = 69,
parameterHints = 70,
peekWidgetDefaultFocus = 71,
definitionLinkOpensInPeek = 72,
quickSuggestions = 73,
quickSuggestionsDelay = 74,
readOnly = 75,
renameOnType = 76,
renderControlCharacters = 77,
renderIndentGuides = 78,
renderFinalNewline = 79,
renderLineHighlight = 80,
renderLineHighlightOnlyWhenFocus = 81,
renderValidationDecorations = 82,
renderWhitespace = 83,
revealHorizontalRightPadding = 84,
roundedSelection = 85,
rulers = 86,
scrollbar = 87,
scrollBeyondLastColumn = 88,
scrollBeyondLastLine = 89,
scrollPredominantAxis = 90,
selectionClipboard = 91,
selectionHighlight = 92,
selectOnLineNumbers = 93,
showFoldingControls = 94,
showUnused = 95,
snippetSuggestions = 96,
smartSelect = 97,
smoothScrolling = 98,
stickyTabStops = 99,
stopRenderingLineAfter = 100,
suggest = 101,
suggestFontSize = 102,
suggestLineHeight = 103,
suggestOnTriggerCharacters = 104,
suggestSelection = 105,
tabCompletion = 106,
tabIndex = 107,
unusualLineTerminators = 108,
useTabStops = 109,
wordSeparators = 110,
wordWrap = 111,
wordWrapBreakAfterCharacters = 112,
wordWrapBreakBeforeCharacters = 113,
wordWrapColumn = 114,
wordWrapOverride1 = 115,
wordWrapOverride2 = 116,
wrappingIndent = 117,
wrappingStrategy = 118,
showDeprecated = 119,
editorClassName = 120,
pixelRatio = 121,
tabFocusMode = 122,
layoutInfo = 123,
wrappingInfo = 124
}
/**

View File

@@ -11,6 +11,8 @@ import { ScrollType } from 'vs/editor/common/editorCommon';
import { IModelDecorationsChangedEvent } from 'vs/editor/common/model/textModelEvents';
export const enum ViewEventType {
ViewCompositionStart,
ViewCompositionEnd,
ViewConfigurationChanged,
ViewCursorStateChanged,
ViewDecorationsChanged,
@@ -29,6 +31,16 @@ export const enum ViewEventType {
ViewZonesChanged,
}
export class ViewCompositionStartEvent {
public readonly type = ViewEventType.ViewCompositionStart;
constructor() { }
}
export class ViewCompositionEndEvent {
public readonly type = ViewEventType.ViewCompositionEnd;
constructor() { }
}
export class ViewConfigurationChangedEvent {
public readonly type = ViewEventType.ViewConfigurationChanged;
@@ -285,7 +297,9 @@ export class ViewZonesChangedEvent {
}
export type ViewEvent = (
ViewConfigurationChangedEvent
ViewCompositionStartEvent
| ViewCompositionEndEvent
| ViewConfigurationChangedEvent
| ViewCursorStateChangedEvent
| ViewDecorationsChangedEvent
| ViewFlushedEvent

View File

@@ -42,6 +42,24 @@ export class LineDecoration {
return true;
}
public static extractWrapped(arr: LineDecoration[], startOffset: number, endOffset: number): LineDecoration[] {
if (arr.length === 0) {
return arr;
}
const startColumn = startOffset + 1;
const endColumn = endOffset + 1;
const lineLength = endOffset - startOffset;
const r = [];
let rLength = 0;
for (const dec of arr) {
if (dec.endColumn <= startColumn || dec.startColumn >= endColumn) {
continue;
}
r[rLength++] = new LineDecoration(Math.max(1, dec.startColumn - startColumn + 1), Math.min(lineLength + 1, dec.endColumn - startColumn + 1), dec.className, dec.type);
}
return r;
}
public static filter(lineDecorations: InlineDecoration[], lineNumber: number, minLineColumn: number, maxLineColumn: number): LineDecoration[] {
if (lineDecorations.length === 0) {
return [];

View File

@@ -546,6 +546,23 @@ export class LinesLayout {
return verticalOffset > totalHeight;
}
public isInTopPadding(verticalOffset: number): boolean {
if (this._paddingTop === 0) {
return false;
}
this._checkPendingChanges();
return (verticalOffset < this._paddingTop);
}
public isInBottomPadding(verticalOffset: number): boolean {
if (this._paddingBottom === 0) {
return false;
}
this._checkPendingChanges();
const totalHeight = this.getLinesTotalHeight();
return (verticalOffset >= totalHeight - this._paddingBottom);
}
/**
* Find the first line number that is at or after vertical offset `verticalOffset`.
* i.e. if getVerticalOffsetForLine(line) is x and getVerticalOffsetForLine(line + 1) is y, then

View File

@@ -364,6 +364,13 @@ export class ViewLayout extends Disposable implements IViewLayout {
public isAfterLines(verticalOffset: number): boolean {
return this._linesLayout.isAfterLines(verticalOffset);
}
public isInTopPadding(verticalOffset: number): boolean {
return this._linesLayout.isInTopPadding(verticalOffset);
}
isInBottomPadding(verticalOffset: number): boolean {
return this._linesLayout.isInBottomPadding(verticalOffset);
}
public getLineNumberAtVerticalOffset(verticalOffset: number): number {
return this._linesLayout.getLineNumberAtOrAfterVerticalOffset(verticalOffset);
}

View File

@@ -127,7 +127,7 @@ export class RenderLineInput {
this.containsRTL = containsRTL;
this.fauxIndentLength = fauxIndentLength;
this.lineTokens = lineTokens;
this.lineDecorations = lineDecorations;
this.lineDecorations = lineDecorations.sort(LineDecoration.compare);
this.tabSize = tabSize;
this.startVisibleColumn = startVisibleColumn;
this.spaceWidth = spaceWidth;

View File

@@ -7,8 +7,9 @@ import { CharCode } from 'vs/base/common/charCode';
import * as strings from 'vs/base/common/strings';
import { WrappingIndent, IComputedEditorOptions, EditorOption } from 'vs/editor/common/config/editorOptions';
import { CharacterClassifier } from 'vs/editor/common/core/characterClassifier';
import { ILineBreaksComputerFactory, LineBreakData, ILineBreaksComputer } from 'vs/editor/common/viewModel/splitLinesCollection';
import { ILineBreaksComputerFactory } from 'vs/editor/common/viewModel/splitLinesCollection';
import { FontInfo } from 'vs/editor/common/config/fontInfo';
import { ILineBreaksComputer, LineBreakData } from 'vs/editor/common/viewModel/viewModel';
const enum CharacterClass {
NONE = 0,

View File

@@ -12,69 +12,11 @@ import { EndOfLinePreference, IActiveIndentGuideInfo, IModelDecoration, IModelDe
import { ModelDecorationOptions, ModelDecorationOverviewRulerOptions } from 'vs/editor/common/model/textModel';
import * as viewEvents from 'vs/editor/common/view/viewEvents';
import { PrefixSumIndexOfResult } from 'vs/editor/common/viewModel/prefixSumComputer';
import { ICoordinatesConverter, IOverviewRulerDecorations, ViewLineData } from 'vs/editor/common/viewModel/viewModel';
import { ICoordinatesConverter, ILineBreaksComputer, IOverviewRulerDecorations, LineBreakData, ViewLineData } from 'vs/editor/common/viewModel/viewModel';
import { IDisposable } from 'vs/base/common/lifecycle';
import { FontInfo } from 'vs/editor/common/config/fontInfo';
import { EditorTheme } from 'vs/editor/common/view/viewContext';
export class OutputPosition {
outputLineIndex: number;
outputOffset: number;
constructor(outputLineIndex: number, outputOffset: number) {
this.outputLineIndex = outputLineIndex;
this.outputOffset = outputOffset;
}
}
export class LineBreakData {
constructor(
public breakOffsets: number[],
public breakOffsetsVisibleColumn: number[],
public wrappedTextIndentLength: number
) { }
public static getInputOffsetOfOutputPosition(breakOffsets: number[], outputLineIndex: number, outputOffset: number): number {
if (outputLineIndex === 0) {
return outputOffset;
} else {
return breakOffsets[outputLineIndex - 1] + outputOffset;
}
}
public static getOutputPositionOfInputOffset(breakOffsets: number[], inputOffset: number): OutputPosition {
let low = 0;
let high = breakOffsets.length - 1;
let mid = 0;
let midStart = 0;
while (low <= high) {
mid = low + ((high - low) / 2) | 0;
const midStop = breakOffsets[mid];
midStart = mid > 0 ? breakOffsets[mid - 1] : 0;
if (inputOffset < midStart) {
high = mid - 1;
} else if (inputOffset >= midStop) {
low = mid + 1;
} else {
break;
}
}
return new OutputPosition(mid, inputOffset - midStart);
}
}
export interface ILineBreaksComputer {
/**
* Pass in `previousLineBreakData` if the only difference is in breaking columns!!!
*/
addRequest(lineText: string, previousLineBreakData: LineBreakData | null): void;
finalize(): (LineBreakData | null)[];
}
export interface ILineBreaksComputerFactory {
createLineBreaksComputer(fontInfo: FontInfo, tabSize: number, wrappingColumn: number, wrappingIndent: WrappingIndent): ILineBreaksComputer;
}
@@ -174,6 +116,10 @@ export class CoordinatesConverter implements ICoordinatesConverter {
public modelPositionIsVisible(modelPosition: Position): boolean {
return this._lines.modelPositionIsVisible(modelPosition.lineNumber, modelPosition.column);
}
public getModelLineViewLineCount(modelLineNumber: number): number {
return this._lines.getModelLineViewLineCount(modelLineNumber);
}
}
const enum IndentGuideRepeatOption {
@@ -473,6 +419,14 @@ export class SplitLinesCollection implements IViewModelLinesCollection {
return this.lines[modelLineNumber - 1].isVisible();
}
public getModelLineViewLineCount(modelLineNumber: number): number {
if (modelLineNumber < 1 || modelLineNumber > this.lines.length) {
// invalid arguments
return 1;
}
return this.lines[modelLineNumber - 1].getViewLineCount();
}
public setTabSize(newTabSize: number): boolean {
if (this.tabSize === newTabSize) {
return false;
@@ -1431,6 +1385,9 @@ export class IdentityCoordinatesConverter implements ICoordinatesConverter {
return true;
}
public getModelLineViewLineCount(modelLineNumber: number): number {
return 1;
}
}
export class IdentityLinesCollection implements IViewModelLinesCollection {

View File

@@ -33,10 +33,15 @@ export class ViewEventHandler extends Disposable {
// --- begin event handlers
public onCompositionStart(e: viewEvents.ViewCompositionStartEvent): boolean {
return false;
}
public onCompositionEnd(e: viewEvents.ViewCompositionEndEvent): boolean {
return false;
}
public onConfigurationChanged(e: viewEvents.ViewConfigurationChangedEvent): boolean {
return false;
}
public onCursorStateChanged(e: viewEvents.ViewCursorStateChangedEvent): boolean {
return false;
}
@@ -94,6 +99,18 @@ export class ViewEventHandler extends Disposable {
switch (e.type) {
case viewEvents.ViewEventType.ViewCompositionStart:
if (this.onCompositionStart(e)) {
shouldRender = true;
}
break;
case viewEvents.ViewEventType.ViewCompositionEnd:
if (this.onCompositionEnd(e)) {
shouldRender = true;
}
break;
case viewEvents.ViewEventType.ViewConfigurationChanged:
if (this.onConfigurationChanged(e)) {
shouldRender = true;

View File

@@ -61,6 +61,8 @@ export interface IViewLayout {
getWhitespaces(): IEditorWhitespace[];
isAfterLines(verticalOffset: number): boolean;
isInTopPadding(verticalOffset: number): boolean;
isInBottomPadding(verticalOffset: number): boolean;
getLineNumberAtVerticalOffset(verticalOffset: number): number;
getVerticalOffsetForLineNumber(lineNumber: number): number;
getWhitespaceAtVerticalOffset(verticalOffset: number): IViewWhitespaceViewportData | null;
@@ -82,6 +84,65 @@ export interface ICoordinatesConverter {
convertModelPositionToViewPosition(modelPosition: Position): Position;
convertModelRangeToViewRange(modelRange: Range): Range;
modelPositionIsVisible(modelPosition: Position): boolean;
getModelLineViewLineCount(modelLineNumber: number): number;
}
export class OutputPosition {
outputLineIndex: number;
outputOffset: number;
constructor(outputLineIndex: number, outputOffset: number) {
this.outputLineIndex = outputLineIndex;
this.outputOffset = outputOffset;
}
}
export class LineBreakData {
constructor(
public breakOffsets: number[],
public breakOffsetsVisibleColumn: number[],
public wrappedTextIndentLength: number
) { }
public static getInputOffsetOfOutputPosition(breakOffsets: number[], outputLineIndex: number, outputOffset: number): number {
if (outputLineIndex === 0) {
return outputOffset;
} else {
return breakOffsets[outputLineIndex - 1] + outputOffset;
}
}
public static getOutputPositionOfInputOffset(breakOffsets: number[], inputOffset: number): OutputPosition {
let low = 0;
let high = breakOffsets.length - 1;
let mid = 0;
let midStart = 0;
while (low <= high) {
mid = low + ((high - low) / 2) | 0;
const midStop = breakOffsets[mid];
midStart = mid > 0 ? breakOffsets[mid - 1] : 0;
if (inputOffset < midStart) {
high = mid - 1;
} else if (inputOffset >= midStop) {
low = mid + 1;
} else {
break;
}
}
return new OutputPosition(mid, inputOffset - midStart);
}
}
export interface ILineBreaksComputer {
/**
* Pass in `previousLineBreakData` if the only difference is in breaking columns!!!
*/
addRequest(lineText: string, previousLineBreakData: LineBreakData | null): void;
finalize(): (LineBreakData | null)[];
}
export interface IViewModel extends ICursorSimpleModel {
@@ -103,6 +164,8 @@ export interface IViewModel extends ICursorSimpleModel {
setViewport(startLineNumber: number, endLineNumber: number, centeredLineNumber: number): void;
tokenizeViewport(): void;
setHasFocus(hasFocus: boolean): void;
onCompositionStart(): void;
onCompositionEnd(): void;
onDidColorThemeChange(): void;
getDecorationsInViewport(visibleRange: Range): ViewModelDecoration[];
@@ -142,6 +205,7 @@ export interface IViewModel extends ICursorSimpleModel {
//#endregion
createLineBreaksComputer(): ILineBreaksComputer;
//#region cursor
getPrimaryCursorState(): CursorState;

View File

@@ -21,7 +21,7 @@ import { MinimapTokensColorTracker } from 'vs/editor/common/viewModel/minimapTok
import * as viewEvents from 'vs/editor/common/view/viewEvents';
import { ViewLayout } from 'vs/editor/common/viewLayout/viewLayout';
import { IViewModelLinesCollection, IdentityLinesCollection, SplitLinesCollection, ILineBreaksComputerFactory } from 'vs/editor/common/viewModel/splitLinesCollection';
import { ICoordinatesConverter, IOverviewRulerDecorations, IViewModel, MinimapLinesRenderingData, ViewLineData, ViewLineRenderingData, ViewModelDecoration } from 'vs/editor/common/viewModel/viewModel';
import { ICoordinatesConverter, ILineBreaksComputer, IOverviewRulerDecorations, IViewModel, MinimapLinesRenderingData, ViewLineData, ViewLineRenderingData, ViewModelDecoration } from 'vs/editor/common/viewModel/viewModel';
import { ViewModelDecorations } from 'vs/editor/common/viewModel/viewModelDecorations';
import { RunOnceScheduler } from 'vs/base/common/async';
import * as platform from 'vs/base/common/platform';
@@ -153,6 +153,10 @@ export class ViewModel extends Disposable implements IViewModel {
this._eventDispatcher.dispose();
}
public createLineBreaksComputer(): ILineBreaksComputer {
return this._lines.createLineBreaksComputer();
}
public addViewEventHandler(eventHandler: ViewEventHandler): void {
this._eventDispatcher.addViewEventHandler(eventHandler);
}
@@ -179,6 +183,14 @@ export class ViewModel extends Disposable implements IViewModel {
this._eventDispatcher.emitOutgoingEvent(new FocusChangedEvent(!hasFocus, hasFocus));
}
public onCompositionStart(): void {
this._eventDispatcher.emitSingleViewEvent(new viewEvents.ViewCompositionStartEvent());
}
public onCompositionEnd(): void {
this._eventDispatcher.emitSingleViewEvent(new viewEvents.ViewCompositionEndEvent());
}
public onDidColorThemeChange(): void {
this._eventDispatcher.emitSingleViewEvent(new viewEvents.ViewThemeChangedEvent());
}