mirror of
https://github.com/ckaczor/azuredatastudio.git
synced 2026-02-15 02:48:30 -05:00
Merge from vscode e3c4990c67c40213af168300d1cfeb71d680f877 (#16569)
This commit is contained in:
@@ -24,6 +24,9 @@ export interface IShiftCommandOpts {
|
||||
|
||||
const repeatCache: { [str: string]: string[]; } = Object.create(null);
|
||||
export function cachedStringRepeat(str: string, count: number): string {
|
||||
if (count <= 0) {
|
||||
return '';
|
||||
}
|
||||
if (!repeatCache[str]) {
|
||||
repeatCache[str] = ['', str];
|
||||
}
|
||||
|
||||
@@ -204,6 +204,7 @@ function migrateOptions(options: IEditorOptions): void {
|
||||
mapping['method'] = 'showMethods';
|
||||
mapping['function'] = 'showFunctions';
|
||||
mapping['constructor'] = 'showConstructors';
|
||||
mapping['deprecated'] = 'showDeprecated';
|
||||
mapping['field'] = 'showFields';
|
||||
mapping['variable'] = 'showVariables';
|
||||
mapping['class'] = 'showClasses';
|
||||
|
||||
@@ -382,8 +382,9 @@ export interface IEditorOptions {
|
||||
* Suggest options.
|
||||
*/
|
||||
suggest?: ISuggestOptions;
|
||||
inlineSuggest?: IInlineSuggestOptions;
|
||||
/**
|
||||
* Smart select opptions;
|
||||
* Smart select options.
|
||||
*/
|
||||
smartSelect?: ISmartSelectOptions;
|
||||
/**
|
||||
@@ -637,7 +638,11 @@ export interface IEditorOptions {
|
||||
/**
|
||||
* Control the behavior and rendering of the inline hints.
|
||||
*/
|
||||
inlineHints?: IEditorInlineHintsOptions;
|
||||
inlayHints?: IEditorInlayHintsOptions;
|
||||
/**
|
||||
* Control if the editor should use shadow DOM.
|
||||
*/
|
||||
useShadowDOM?: boolean;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -2401,12 +2406,12 @@ class EditorLightbulb extends BaseEditorOption<EditorOption.lightbulb, EditorLig
|
||||
|
||||
//#endregion
|
||||
|
||||
//#region inlineHints
|
||||
//#region inlayHints
|
||||
|
||||
/**
|
||||
* Configuration options for editor inlineHints
|
||||
* Configuration options for editor inlayHints
|
||||
*/
|
||||
export interface IEditorInlineHintsOptions {
|
||||
export interface IEditorInlayHintsOptions {
|
||||
/**
|
||||
* Enable the inline hints.
|
||||
* Defaults to true.
|
||||
@@ -2426,39 +2431,39 @@ export interface IEditorInlineHintsOptions {
|
||||
fontFamily?: string;
|
||||
}
|
||||
|
||||
export type EditorInlineHintsOptions = Readonly<Required<IEditorInlineHintsOptions>>;
|
||||
export type EditorInlayHintsOptions = Readonly<Required<IEditorInlayHintsOptions>>;
|
||||
|
||||
class EditorInlineHints extends BaseEditorOption<EditorOption.inlineHints, EditorInlineHintsOptions> {
|
||||
class EditorInlayHints extends BaseEditorOption<EditorOption.inlayHints, EditorInlayHintsOptions> {
|
||||
|
||||
constructor() {
|
||||
const defaults: EditorInlineHintsOptions = { enabled: true, fontSize: 0, fontFamily: EDITOR_FONT_DEFAULTS.fontFamily };
|
||||
const defaults: EditorInlayHintsOptions = { enabled: true, fontSize: 0, fontFamily: EDITOR_FONT_DEFAULTS.fontFamily };
|
||||
super(
|
||||
EditorOption.inlineHints, 'inlineHints', defaults,
|
||||
EditorOption.inlayHints, 'inlayHints', defaults,
|
||||
{
|
||||
'editor.inlineHints.enabled': {
|
||||
'editor.inlayHints.enabled': {
|
||||
type: 'boolean',
|
||||
default: defaults.enabled,
|
||||
description: nls.localize('inlineHints.enable', "Enables the inline hints in the editor.")
|
||||
description: nls.localize('inlayHints.enable', "Enables the inlay hints in the editor.")
|
||||
},
|
||||
'editor.inlineHints.fontSize': {
|
||||
'editor.inlayHints.fontSize': {
|
||||
type: 'number',
|
||||
default: defaults.fontSize,
|
||||
description: nls.localize('inlineHints.fontSize', "Controls font size of inline hints in the editor. When set to `0`, the 90% of `#editor.fontSize#` is used.")
|
||||
description: nls.localize('inlayHints.fontSize', "Controls font size of inlay hints in the editor. When set to `0`, the 90% of `#editor.fontSize#` is used.")
|
||||
},
|
||||
'editor.inlineHints.fontFamily': {
|
||||
'editor.inlayHints.fontFamily': {
|
||||
type: 'string',
|
||||
default: defaults.fontFamily,
|
||||
description: nls.localize('inlineHints.fontFamily', "Controls font family of inline hints in the editor.")
|
||||
description: nls.localize('inlayHints.fontFamily', "Controls font family of inlay hints in the editor.")
|
||||
},
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
public validate(_input: any): EditorInlineHintsOptions {
|
||||
public validate(_input: any): EditorInlayHintsOptions {
|
||||
if (!_input || typeof _input !== 'object') {
|
||||
return this.defaultValue;
|
||||
}
|
||||
const input = _input as IEditorInlineHintsOptions;
|
||||
const input = _input as IEditorInlayHintsOptions;
|
||||
return {
|
||||
enabled: boolean(input.enabled, this.defaultValue.enabled),
|
||||
fontSize: EditorIntOption.clampedInt(input.fontSize, this.defaultValue.fontSize, 0, 100),
|
||||
@@ -3141,6 +3146,51 @@ class EditorScrollbar extends BaseEditorOption<EditorOption.scrollbar, InternalE
|
||||
|
||||
//#endregion
|
||||
|
||||
//#region inlineSuggest
|
||||
|
||||
export interface IInlineSuggestOptions {
|
||||
/**
|
||||
* Enable or disable the rendering of automatic inline completions.
|
||||
*/
|
||||
enabled?: boolean;
|
||||
}
|
||||
|
||||
export type InternalInlineSuggestOptions = Readonly<Required<IInlineSuggestOptions>>;
|
||||
|
||||
/**
|
||||
* Configuration options for inline suggestions
|
||||
*/
|
||||
class InlineEditorSuggest extends BaseEditorOption<EditorOption.inlineSuggest, InternalInlineSuggestOptions> {
|
||||
constructor() {
|
||||
const defaults: InternalInlineSuggestOptions = {
|
||||
enabled: false
|
||||
};
|
||||
|
||||
super(
|
||||
EditorOption.inlineSuggest, 'inlineSuggest', defaults,
|
||||
{
|
||||
'editor.inlineSuggest.enabled': {
|
||||
type: 'boolean',
|
||||
default: defaults.enabled,
|
||||
description: nls.localize('inlineSuggest.enabled', "Controls whether to automatically show inline suggestions in the editor.")
|
||||
},
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
public validate(_input: any): InternalInlineSuggestOptions {
|
||||
if (!_input || typeof _input !== 'object') {
|
||||
return this.defaultValue;
|
||||
}
|
||||
const input = _input as IInlineSuggestOptions;
|
||||
return {
|
||||
enabled: boolean(input.enabled, this.defaultValue.enabled),
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
//#endregion
|
||||
|
||||
//#region suggest
|
||||
|
||||
/**
|
||||
@@ -3175,6 +3225,10 @@ export interface ISuggestOptions {
|
||||
* Enable or disable the suggest status bar.
|
||||
*/
|
||||
showStatusBar?: boolean;
|
||||
/**
|
||||
* Enable or disable the rendering of the suggestion preview.
|
||||
*/
|
||||
preview?: boolean;
|
||||
/**
|
||||
* Show details inline with the label. Defaults to true.
|
||||
*/
|
||||
@@ -3191,6 +3245,10 @@ export interface ISuggestOptions {
|
||||
* Show constructor-suggestions.
|
||||
*/
|
||||
showConstructors?: boolean;
|
||||
/**
|
||||
* Show deprecated-suggestions.
|
||||
*/
|
||||
showDeprecated?: boolean;
|
||||
/**
|
||||
* Show field-suggestions.
|
||||
*/
|
||||
@@ -3302,10 +3360,12 @@ class EditorSuggest extends BaseEditorOption<EditorOption.suggest, InternalSugge
|
||||
shareSuggestSelections: false,
|
||||
showIcons: true,
|
||||
showStatusBar: false,
|
||||
preview: false,
|
||||
showInlineDetails: true,
|
||||
showMethods: true,
|
||||
showFunctions: true,
|
||||
showConstructors: true,
|
||||
showDeprecated: true,
|
||||
showFields: true,
|
||||
showVariables: true,
|
||||
showClasses: true,
|
||||
@@ -3374,7 +3434,11 @@ 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.preview': {
|
||||
type: 'boolean',
|
||||
default: defaults.preview,
|
||||
description: nls.localize('suggest.preview', "Controls whether to preview the suggestion outcome in the editor.")
|
||||
},
|
||||
'editor.suggest.showInlineDetails': {
|
||||
type: 'boolean',
|
||||
default: defaults.showInlineDetails,
|
||||
@@ -3403,6 +3467,11 @@ class EditorSuggest extends BaseEditorOption<EditorOption.suggest, InternalSugge
|
||||
default: true,
|
||||
markdownDescription: nls.localize('editor.suggest.showConstructors', "When enabled IntelliSense shows `constructor`-suggestions.")
|
||||
},
|
||||
'editor.suggest.showDeprecated': {
|
||||
type: 'boolean',
|
||||
default: true,
|
||||
markdownDescription: nls.localize('editor.suggest.showDeprecated', "When enabled IntelliSense shows `deprecated`-suggestions.")
|
||||
},
|
||||
'editor.suggest.showFields': {
|
||||
type: 'boolean',
|
||||
default: true,
|
||||
@@ -3545,10 +3614,12 @@ class EditorSuggest extends BaseEditorOption<EditorOption.suggest, InternalSugge
|
||||
shareSuggestSelections: boolean(input.shareSuggestSelections, this.defaultValue.shareSuggestSelections),
|
||||
showIcons: boolean(input.showIcons, this.defaultValue.showIcons),
|
||||
showStatusBar: boolean(input.showStatusBar, this.defaultValue.showStatusBar),
|
||||
preview: boolean(input.preview, this.defaultValue.preview),
|
||||
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),
|
||||
showDeprecated: boolean(input.showDeprecated, this.defaultValue.showDeprecated),
|
||||
showFields: boolean(input.showFields, this.defaultValue.showFields),
|
||||
showVariables: boolean(input.showVariables, this.defaultValue.showVariables),
|
||||
showClasses: boolean(input.showClasses, this.defaultValue.showClasses),
|
||||
@@ -3793,6 +3864,7 @@ export const enum EditorOption {
|
||||
highlightActiveIndentGuide,
|
||||
hover,
|
||||
inDiffEditor,
|
||||
inlineSuggest,
|
||||
letterSpacing,
|
||||
lightbulb,
|
||||
lineDecorationsWidth,
|
||||
@@ -3852,6 +3924,7 @@ export const enum EditorOption {
|
||||
tabCompletion,
|
||||
tabIndex,
|
||||
unusualLineTerminators,
|
||||
useShadowDOM,
|
||||
useTabStops,
|
||||
wordSeparators,
|
||||
wordWrap,
|
||||
@@ -3863,7 +3936,7 @@ export const enum EditorOption {
|
||||
wrappingIndent,
|
||||
wrappingStrategy,
|
||||
showDeprecated,
|
||||
inlineHints,
|
||||
inlayHints,
|
||||
// Leave these at the end (because they have dependencies!)
|
||||
editorClassName,
|
||||
pixelRatio,
|
||||
@@ -4385,7 +4458,7 @@ export const EditorOptions = {
|
||||
EditorOption.showDeprecated, 'showDeprecated', true,
|
||||
{ description: nls.localize('showDeprecated', "Controls strikethrough deprecated variables.") }
|
||||
)),
|
||||
inlineHints: register(new EditorInlineHints()),
|
||||
inlayHints: register(new EditorInlayHints()),
|
||||
snippetSuggestions: register(new EditorStringEnumOption(
|
||||
EditorOption.snippetSuggestions, 'snippetSuggestions',
|
||||
'inline' as 'top' | 'bottom' | 'inline' | 'none',
|
||||
@@ -4410,6 +4483,7 @@ export const EditorOptions = {
|
||||
10000, -1, Constants.MAX_SAFE_SMALL_INTEGER,
|
||||
)),
|
||||
suggest: register(new EditorSuggest()),
|
||||
inlineSuggest: register(new InlineEditorSuggest()),
|
||||
suggestFontSize: register(new EditorIntOption(
|
||||
EditorOption.suggestFontSize, 'suggestFontSize',
|
||||
0, 0, 1000,
|
||||
@@ -4467,6 +4541,9 @@ export const EditorOptions = {
|
||||
description: nls.localize('unusualLineTerminators', "Remove unusual line terminators that might cause problems.")
|
||||
}
|
||||
)),
|
||||
useShadowDOM: register(new EditorBooleanOption(
|
||||
EditorOption.useShadowDOM, 'useShadowDOM', true
|
||||
)),
|
||||
useTabStops: register(new EditorBooleanOption(
|
||||
EditorOption.useTabStops, 'useTabStops', true,
|
||||
{ description: nls.localize('useTabStops', "Inserting and deleting whitespace follows tab stops.") }
|
||||
|
||||
@@ -415,6 +415,7 @@ export class Cursor extends Disposable {
|
||||
autoClosedCharactersDeltaDecorations.push({
|
||||
range: autoClosedCharactersRanges[i],
|
||||
options: {
|
||||
description: 'auto-closed-character',
|
||||
inlineClassName: 'auto-closed-character',
|
||||
stickiness: TrackedRangeStickiness.NeverGrowsWhenTypingAtEdges
|
||||
}
|
||||
@@ -422,6 +423,7 @@ export class Cursor extends Disposable {
|
||||
autoClosedEnclosingDeltaDecorations.push({
|
||||
range: autoClosedEnclosingRanges[i],
|
||||
options: {
|
||||
description: 'auto-closed-enclosing',
|
||||
stickiness: TrackedRangeStickiness.NeverGrowsWhenTypingAtEdges
|
||||
}
|
||||
});
|
||||
|
||||
@@ -11,7 +11,7 @@ import { Position } from 'vs/editor/common/core/position';
|
||||
import { Range } from 'vs/editor/common/core/range';
|
||||
import { ISelection, Selection } from 'vs/editor/common/core/selection';
|
||||
import { ICommand, IConfiguration } from 'vs/editor/common/editorCommon';
|
||||
import { ITextModel, TextModelResolvedOptions } from 'vs/editor/common/model';
|
||||
import { ITextModel, PositionNormalizationAffinity, TextModelResolvedOptions } from 'vs/editor/common/model';
|
||||
import { TextModel } from 'vs/editor/common/model/textModel';
|
||||
import { LanguageIdentifier } from 'vs/editor/common/modes';
|
||||
import { AutoClosingPairs, IAutoClosingPair } from 'vs/editor/common/modes/languageConfiguration';
|
||||
@@ -39,9 +39,11 @@ export const enum RevealTarget {
|
||||
*/
|
||||
export const enum EditOperationType {
|
||||
Other = 0,
|
||||
Typing = 1,
|
||||
DeletingLeft = 2,
|
||||
DeletingRight = 3
|
||||
DeletingRight = 3,
|
||||
TypingOther = 4,
|
||||
TypingFirstSpace = 5,
|
||||
TypingConsecutiveSpace = 6,
|
||||
}
|
||||
|
||||
export interface CharacterMap {
|
||||
@@ -219,6 +221,12 @@ export interface ICursorSimpleModel {
|
||||
getLineMaxColumn(lineNumber: number): number;
|
||||
getLineFirstNonWhitespaceColumn(lineNumber: number): number;
|
||||
getLineLastNonWhitespaceColumn(lineNumber: number): number;
|
||||
normalizePosition(position: Position, affinity: PositionNormalizationAffinity): Position;
|
||||
/**
|
||||
* Gets the column at which indentation stops at a given line.
|
||||
* @internal
|
||||
*/
|
||||
getLineIndentColumn(lineNumber: number): number;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -450,6 +458,55 @@ export class CursorColumns {
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an array that maps one based columns to one based visible columns. The entry at position 0 is -1.
|
||||
*/
|
||||
public static visibleColumnsByColumns(lineContent: string, tabSize: number): number[] {
|
||||
const endOffset = lineContent.length;
|
||||
|
||||
let result = new Array<number>();
|
||||
result.push(-1);
|
||||
let pos = 0;
|
||||
let i = 0;
|
||||
while (i < endOffset) {
|
||||
const codePoint = strings.getNextCodePoint(lineContent, endOffset, i);
|
||||
i += (codePoint >= Constants.UNICODE_SUPPLEMENTARY_PLANE_BEGIN ? 2 : 1);
|
||||
|
||||
result.push(pos);
|
||||
if (codePoint >= Constants.UNICODE_SUPPLEMENTARY_PLANE_BEGIN) {
|
||||
result.push(pos);
|
||||
}
|
||||
|
||||
if (codePoint === CharCode.Tab) {
|
||||
pos = CursorColumns.nextRenderTabStop(pos, tabSize);
|
||||
} else {
|
||||
let graphemeBreakType = strings.getGraphemeBreakType(codePoint);
|
||||
while (i < endOffset) {
|
||||
const nextCodePoint = strings.getNextCodePoint(lineContent, endOffset, i);
|
||||
const nextGraphemeBreakType = strings.getGraphemeBreakType(nextCodePoint);
|
||||
if (strings.breakBetweenGraphemeBreakType(graphemeBreakType, nextGraphemeBreakType)) {
|
||||
break;
|
||||
}
|
||||
i += (nextCodePoint >= Constants.UNICODE_SUPPLEMENTARY_PLANE_BEGIN ? 2 : 1);
|
||||
|
||||
result.push(pos);
|
||||
if (codePoint >= Constants.UNICODE_SUPPLEMENTARY_PLANE_BEGIN) {
|
||||
result.push(pos);
|
||||
}
|
||||
|
||||
graphemeBreakType = nextGraphemeBreakType;
|
||||
}
|
||||
if (strings.isFullWidthCharacter(codePoint) || strings.isEmojiImprecise(codePoint)) {
|
||||
pos = pos + 2;
|
||||
} else {
|
||||
pos = pos + 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
result.push(pos);
|
||||
return result;
|
||||
}
|
||||
|
||||
public static toStatusbarColumn(lineContent: string, column: number, tabSize: number): number {
|
||||
const lineContentLength = lineContent.length;
|
||||
const endOffset = column - 1 < lineContentLength ? column - 1 : lineContentLength;
|
||||
@@ -562,14 +619,14 @@ export class CursorColumns {
|
||||
* 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;
|
||||
return Math.max(0, column - 1 - (column - 1) % tabSize);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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;
|
||||
return Math.max(0, column - 1 - (column - 1) % indentSize);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -12,6 +12,7 @@ import { Range } from 'vs/editor/common/core/range';
|
||||
import { Selection } from 'vs/editor/common/core/selection';
|
||||
import { ICommand } from 'vs/editor/common/editorCommon';
|
||||
import { StandardAutoClosingPairConditional } from 'vs/editor/common/modes/languageConfiguration';
|
||||
import { Position } from 'vs/editor/common/core/position';
|
||||
|
||||
export class DeleteOperations {
|
||||
|
||||
@@ -25,7 +26,7 @@ export class DeleteOperations {
|
||||
|
||||
if (deleteSelection.isEmpty()) {
|
||||
let position = selection.getPosition();
|
||||
let rightOfPosition = MoveOperations.right(config, model, position.lineNumber, position.column);
|
||||
let rightOfPosition = MoveOperations.right(config, model, position);
|
||||
deleteSelection = new Range(
|
||||
rightOfPosition.lineNumber,
|
||||
rightOfPosition.column,
|
||||
@@ -141,63 +142,72 @@ export class DeleteOperations {
|
||||
}
|
||||
|
||||
public static deleteLeft(prevEditOperationType: EditOperationType, config: CursorConfiguration, model: ICursorSimpleModel, selections: Selection[], autoClosedCharacters: Range[]): [boolean, Array<ICommand | null>] {
|
||||
|
||||
if (this.isAutoClosingPairDelete(config.autoClosingDelete, config.autoClosingBrackets, config.autoClosingQuotes, config.autoClosingPairs.autoClosingPairsOpenByEnd, model, selections, autoClosedCharacters)) {
|
||||
return this._runAutoClosingPairDelete(config, model, selections);
|
||||
}
|
||||
|
||||
let commands: Array<ICommand | null> = [];
|
||||
const commands: Array<ICommand | null> = [];
|
||||
let shouldPushStackElementBefore = (prevEditOperationType !== EditOperationType.DeletingLeft);
|
||||
for (let i = 0, len = selections.length; i < len; i++) {
|
||||
const selection = selections[i];
|
||||
let deleteRange = DeleteOperations.getDeleteRange(selections[i], model, config);
|
||||
|
||||
let deleteSelection: Range = selection;
|
||||
|
||||
if (deleteSelection.isEmpty()) {
|
||||
let position = selection.getPosition();
|
||||
|
||||
if (config.useTabStops && position.column > 1) {
|
||||
let lineContent = model.getLineContent(position.lineNumber);
|
||||
|
||||
let firstNonWhitespaceIndex = strings.firstNonWhitespaceIndex(lineContent);
|
||||
let lastIndentationColumn = (
|
||||
firstNonWhitespaceIndex === -1
|
||||
? /* entire string is whitespace */lineContent.length + 1
|
||||
: firstNonWhitespaceIndex + 1
|
||||
);
|
||||
|
||||
if (position.column <= lastIndentationColumn) {
|
||||
let fromVisibleColumn = CursorColumns.visibleColumnFromColumn2(config, model, position);
|
||||
let toVisibleColumn = CursorColumns.prevIndentTabStop(fromVisibleColumn, config.indentSize);
|
||||
let toColumn = CursorColumns.columnFromVisibleColumn2(config, model, position.lineNumber, toVisibleColumn);
|
||||
deleteSelection = new Range(position.lineNumber, toColumn, position.lineNumber, position.column);
|
||||
} else {
|
||||
deleteSelection = new Range(position.lineNumber, position.column - 1, position.lineNumber, position.column);
|
||||
}
|
||||
} else {
|
||||
let leftOfPosition = MoveOperations.left(config, model, position.lineNumber, position.column);
|
||||
deleteSelection = new Range(
|
||||
leftOfPosition.lineNumber,
|
||||
leftOfPosition.column,
|
||||
position.lineNumber,
|
||||
position.column
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
if (deleteSelection.isEmpty()) {
|
||||
// Probably at beginning of file => ignore
|
||||
// Ignore empty delete ranges, as they have no effect
|
||||
// They happen if the cursor is at the beginning of the file.
|
||||
if (deleteRange.isEmpty()) {
|
||||
commands[i] = null;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (deleteSelection.startLineNumber !== deleteSelection.endLineNumber) {
|
||||
if (deleteRange.startLineNumber !== deleteRange.endLineNumber) {
|
||||
shouldPushStackElementBefore = true;
|
||||
}
|
||||
|
||||
commands[i] = new ReplaceCommand(deleteSelection, '');
|
||||
commands[i] = new ReplaceCommand(deleteRange, '');
|
||||
}
|
||||
return [shouldPushStackElementBefore, commands];
|
||||
|
||||
}
|
||||
|
||||
private static getDeleteRange(selection: Selection, model: ICursorSimpleModel, config: CursorConfiguration,): Range {
|
||||
if (!selection.isEmpty()) {
|
||||
return selection;
|
||||
}
|
||||
|
||||
const position = selection.getPosition();
|
||||
|
||||
// Unintend when using tab stops and cursor is within indentation
|
||||
if (config.useTabStops && position.column > 1) {
|
||||
const lineContent = model.getLineContent(position.lineNumber);
|
||||
|
||||
const firstNonWhitespaceIndex = strings.firstNonWhitespaceIndex(lineContent);
|
||||
const lastIndentationColumn = (
|
||||
firstNonWhitespaceIndex === -1
|
||||
? /* entire string is whitespace */ lineContent.length + 1
|
||||
: firstNonWhitespaceIndex + 1
|
||||
);
|
||||
|
||||
if (position.column <= lastIndentationColumn) {
|
||||
const fromVisibleColumn = CursorColumns.visibleColumnFromColumn2(config, model, position);
|
||||
const toVisibleColumn = CursorColumns.prevIndentTabStop(fromVisibleColumn, config.indentSize);
|
||||
const toColumn = CursorColumns.columnFromVisibleColumn2(config, model, position.lineNumber, toVisibleColumn);
|
||||
return new Range(position.lineNumber, toColumn, position.lineNumber, position.column);
|
||||
}
|
||||
}
|
||||
|
||||
return Range.fromPositions(DeleteOperations.getPositionAfterDeleteLeft(position, model), position);
|
||||
}
|
||||
|
||||
private static getPositionAfterDeleteLeft(position: Position, model: ICursorSimpleModel): Position {
|
||||
if (position.column > 1) {
|
||||
// Convert 1-based columns to 0-based offsets and back.
|
||||
const idx = strings.getLeftDeleteOffset(position.column - 1, model.getLineContent(position.lineNumber));
|
||||
return position.with(undefined, idx + 1);
|
||||
} else if (position.lineNumber > 1) {
|
||||
const newLine = position.lineNumber - 1;
|
||||
return new Position(newLine, model.getLineMaxColumn(newLine));
|
||||
} else {
|
||||
return position;
|
||||
}
|
||||
}
|
||||
|
||||
public static cut(config: CursorConfiguration, model: ICursorSimpleModel, selections: Selection[]): EditOperationResult {
|
||||
|
||||
@@ -419,29 +419,11 @@ export class CursorMoveCommands {
|
||||
}
|
||||
|
||||
private static _moveLeft(viewModel: IViewModel, cursors: CursorState[], inSelectionMode: boolean, noOfColumns: number): PartialCursorState[] {
|
||||
const hasMultipleCursors = (cursors.length > 1);
|
||||
let result: PartialCursorState[] = [];
|
||||
for (let i = 0, len = cursors.length; i < len; i++) {
|
||||
const cursor = cursors[i];
|
||||
const skipWrappingPointStop = hasMultipleCursors || !cursor.viewState.hasSelection();
|
||||
let newViewState = MoveOperations.moveLeft(viewModel.cursorConfig, viewModel, cursor.viewState, inSelectionMode, noOfColumns);
|
||||
|
||||
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) {
|
||||
// stayed on the same model line => pass wrapping point where 2 view positions map to a single model position
|
||||
newViewState = MoveOperations.moveLeft(viewModel.cursorConfig, viewModel, newViewState, inSelectionMode, 1);
|
||||
}
|
||||
}
|
||||
|
||||
result[i] = CursorState.fromViewState(newViewState);
|
||||
}
|
||||
return result;
|
||||
return cursors.map(cursor =>
|
||||
CursorState.fromViewState(
|
||||
MoveOperations.moveLeft(viewModel.cursorConfig, viewModel, cursor.viewState, inSelectionMode, noOfColumns)
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
private static _moveHalfLineLeft(viewModel: IViewModel, cursors: CursorState[], inSelectionMode: boolean): PartialCursorState[] {
|
||||
@@ -456,29 +438,11 @@ export class CursorMoveCommands {
|
||||
}
|
||||
|
||||
private static _moveRight(viewModel: IViewModel, cursors: CursorState[], inSelectionMode: boolean, noOfColumns: number): PartialCursorState[] {
|
||||
const hasMultipleCursors = (cursors.length > 1);
|
||||
let result: PartialCursorState[] = [];
|
||||
for (let i = 0, len = cursors.length; i < len; i++) {
|
||||
const cursor = cursors[i];
|
||||
const skipWrappingPointStop = hasMultipleCursors || !cursor.viewState.hasSelection();
|
||||
let newViewState = MoveOperations.moveRight(viewModel.cursorConfig, viewModel, cursor.viewState, inSelectionMode, noOfColumns);
|
||||
|
||||
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) {
|
||||
// stayed on the same model line => pass wrapping point where 2 view positions map to a single model position
|
||||
newViewState = MoveOperations.moveRight(viewModel.cursorConfig, viewModel, newViewState, inSelectionMode, 1);
|
||||
}
|
||||
}
|
||||
|
||||
result[i] = CursorState.fromViewState(newViewState);
|
||||
}
|
||||
return result;
|
||||
return cursors.map(cursor =>
|
||||
CursorState.fromViewState(
|
||||
MoveOperations.moveRight(viewModel.cursorConfig, viewModel, cursor.viewState, inSelectionMode, noOfColumns)
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
private static _moveHalfLineRight(viewModel: IViewModel, cursors: CursorState[], inSelectionMode: boolean): PartialCursorState[] {
|
||||
|
||||
@@ -9,6 +9,7 @@ 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';
|
||||
import { PositionNormalizationAffinity } from 'vs/editor/common/model';
|
||||
|
||||
export class CursorPosition {
|
||||
_cursorPositionBrand: void;
|
||||
@@ -25,51 +26,86 @@ export class CursorPosition {
|
||||
}
|
||||
|
||||
export class MoveOperations {
|
||||
|
||||
public static leftPosition(model: ICursorSimpleModel, lineNumber: number, column: number): Position {
|
||||
if (column > model.getLineMinColumn(lineNumber)) {
|
||||
column = column - strings.prevCharLength(model.getLineContent(lineNumber), column - 1);
|
||||
} else if (lineNumber > 1) {
|
||||
lineNumber = lineNumber - 1;
|
||||
column = model.getLineMaxColumn(lineNumber);
|
||||
public static leftPosition(model: ICursorSimpleModel, position: Position): Position {
|
||||
if (position.column > model.getLineMinColumn(position.lineNumber)) {
|
||||
return position.delta(undefined, -strings.prevCharLength(model.getLineContent(position.lineNumber), position.column - 1));
|
||||
} else if (position.lineNumber > 1) {
|
||||
const newLineNumber = position.lineNumber - 1;
|
||||
return new Position(newLineNumber, model.getLineMaxColumn(newLineNumber));
|
||||
} else {
|
||||
return position;
|
||||
}
|
||||
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 - 1, tabSize, Direction.Left);
|
||||
if (newPosition === -1 || newPosition + 1 < minColumn) {
|
||||
return this.leftPosition(model, lineNumber, column);
|
||||
private static leftPositionAtomicSoftTabs(model: ICursorSimpleModel, position: Position, tabSize: number): Position {
|
||||
if (position.column <= model.getLineIndentColumn(position.lineNumber)) {
|
||||
const minColumn = model.getLineMinColumn(position.lineNumber);
|
||||
const lineContent = model.getLineContent(position.lineNumber);
|
||||
const newPosition = AtomicTabMoveOperations.atomicPosition(lineContent, position.column - 1, tabSize, Direction.Left);
|
||||
if (newPosition !== -1 && newPosition + 1 >= minColumn) {
|
||||
return new Position(position.lineNumber, newPosition + 1);
|
||||
}
|
||||
}
|
||||
return new Position(lineNumber, newPosition + 1);
|
||||
return this.leftPosition(model, position);
|
||||
}
|
||||
|
||||
public static left(config: CursorConfiguration, model: ICursorSimpleModel, lineNumber: number, column: number): CursorPosition {
|
||||
private static left(config: CursorConfiguration, model: ICursorSimpleModel, position: Position): CursorPosition {
|
||||
const pos = config.stickyTabStops
|
||||
? MoveOperations.leftPositionAtomicSoftTabs(model, lineNumber, column, config.tabSize)
|
||||
: MoveOperations.leftPosition(model, lineNumber, column);
|
||||
? MoveOperations.leftPositionAtomicSoftTabs(model, position, config.tabSize)
|
||||
: MoveOperations.leftPosition(model, position);
|
||||
return new CursorPosition(pos.lineNumber, pos.column, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param noOfColumns Must be either `1`
|
||||
* or `Math.round(viewModel.getLineContent(viewLineNumber).length / 2)` (for half lines).
|
||||
*/
|
||||
public static moveLeft(config: CursorConfiguration, model: ICursorSimpleModel, cursor: SingleCursorState, inSelectionMode: boolean, noOfColumns: number): SingleCursorState {
|
||||
let lineNumber: number,
|
||||
column: number;
|
||||
|
||||
if (cursor.hasSelection() && !inSelectionMode) {
|
||||
// If we are in selection mode, move left without selection cancels selection and puts cursor at the beginning of the selection
|
||||
// If the user has a selection and does not want to extend it,
|
||||
// put the cursor at the beginning of the selection.
|
||||
lineNumber = cursor.selection.startLineNumber;
|
||||
column = cursor.selection.startColumn;
|
||||
} else {
|
||||
let r = MoveOperations.left(config, model, cursor.position.lineNumber, cursor.position.column - (noOfColumns - 1));
|
||||
lineNumber = r.lineNumber;
|
||||
column = r.column;
|
||||
// This has no effect if noOfColumns === 1.
|
||||
// It is ok to do so in the half-line scenario.
|
||||
const pos = cursor.position.delta(undefined, -(noOfColumns - 1));
|
||||
// We clip the position before normalization, as normalization is not defined
|
||||
// for possibly negative columns.
|
||||
const normalizedPos = model.normalizePosition(MoveOperations.clipPositionColumn(pos, model), PositionNormalizationAffinity.Left);
|
||||
const p = MoveOperations.left(config, model, normalizedPos);
|
||||
|
||||
lineNumber = p.lineNumber;
|
||||
column = p.column;
|
||||
}
|
||||
|
||||
return cursor.move(inSelectionMode, lineNumber, column, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adjusts the column so that it is within min/max of the line.
|
||||
*/
|
||||
private static clipPositionColumn(position: Position, model: ICursorSimpleModel): Position {
|
||||
return new Position(
|
||||
position.lineNumber,
|
||||
MoveOperations.clipRange(position.column, model.getLineMinColumn(position.lineNumber),
|
||||
model.getLineMaxColumn(position.lineNumber))
|
||||
);
|
||||
}
|
||||
|
||||
private static clipRange(value: number, min: number, max: number): number {
|
||||
if (value < min) {
|
||||
return min;
|
||||
}
|
||||
if (value > max) {
|
||||
return max;
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
public static rightPosition(model: ICursorSimpleModel, lineNumber: number, column: number): Position {
|
||||
if (column < model.getLineMaxColumn(lineNumber)) {
|
||||
column = column + strings.nextCharLength(model.getLineContent(lineNumber), column - 1);
|
||||
@@ -81,18 +117,20 @@ export class MoveOperations {
|
||||
}
|
||||
|
||||
public static rightPositionAtomicSoftTabs(model: ICursorSimpleModel, lineNumber: number, column: number, tabSize: number, indentSize: number): Position {
|
||||
const lineContent = model.getLineContent(lineNumber);
|
||||
const newPosition = AtomicTabMoveOperations.atomicPosition(lineContent, column - 1, tabSize, Direction.Right);
|
||||
if (newPosition === -1) {
|
||||
return this.rightPosition(model, lineNumber, column);
|
||||
if (column < model.getLineIndentColumn(lineNumber)) {
|
||||
const lineContent = model.getLineContent(lineNumber);
|
||||
const newPosition = AtomicTabMoveOperations.atomicPosition(lineContent, column - 1, tabSize, Direction.Right);
|
||||
if (newPosition !== -1) {
|
||||
return new Position(lineNumber, newPosition + 1);
|
||||
}
|
||||
}
|
||||
return new Position(lineNumber, newPosition + 1);
|
||||
return this.rightPosition(model, lineNumber, column);
|
||||
}
|
||||
|
||||
public static right(config: CursorConfiguration, model: ICursorSimpleModel, lineNumber: number, column: number): CursorPosition {
|
||||
public static right(config: CursorConfiguration, model: ICursorSimpleModel, position: Position): CursorPosition {
|
||||
const pos = config.stickyTabStops
|
||||
? MoveOperations.rightPositionAtomicSoftTabs(model, lineNumber, column, config.tabSize, config.indentSize)
|
||||
: MoveOperations.rightPosition(model, lineNumber, column);
|
||||
? MoveOperations.rightPositionAtomicSoftTabs(model, position.lineNumber, position.column, config.tabSize, config.indentSize)
|
||||
: MoveOperations.rightPosition(model, position.lineNumber, position.column);
|
||||
return new CursorPosition(pos.lineNumber, pos.column, 0);
|
||||
}
|
||||
|
||||
@@ -105,7 +143,9 @@ export class MoveOperations {
|
||||
lineNumber = cursor.selection.endLineNumber;
|
||||
column = cursor.selection.endColumn;
|
||||
} else {
|
||||
let r = MoveOperations.right(config, model, cursor.position.lineNumber, cursor.position.column + (noOfColumns - 1));
|
||||
const pos = cursor.position.delta(undefined, noOfColumns - 1);
|
||||
const normalizedPos = model.normalizePosition(MoveOperations.clipPositionColumn(pos, model), PositionNormalizationAffinity.Right);
|
||||
const r = MoveOperations.right(config, model, normalizedPos);
|
||||
lineNumber = r.lineNumber;
|
||||
column = r.column;
|
||||
}
|
||||
|
||||
@@ -260,8 +260,8 @@ export class TypeOperations {
|
||||
|
||||
public static compositionType(prevEditOperationType: EditOperationType, config: CursorConfiguration, model: ITextModel, selections: Selection[], text: string, replacePrevCharCnt: number, replaceNextCharCnt: number, positionDelta: number): EditOperationResult {
|
||||
const commands = selections.map(selection => this._compositionType(model, selection, text, replacePrevCharCnt, replaceNextCharCnt, positionDelta));
|
||||
return new EditOperationResult(EditOperationType.Typing, commands, {
|
||||
shouldPushStackElementBefore: (prevEditOperationType !== EditOperationType.Typing),
|
||||
return new EditOperationResult(EditOperationType.TypingOther, commands, {
|
||||
shouldPushStackElementBefore: shouldPushStackElementBetween(prevEditOperationType, EditOperationType.TypingOther),
|
||||
shouldPushStackElementAfter: false
|
||||
});
|
||||
}
|
||||
@@ -484,8 +484,8 @@ export class TypeOperations {
|
||||
const typeSelection = new Range(position.lineNumber, position.column, position.lineNumber, position.column + 1);
|
||||
commands[i] = new ReplaceCommand(typeSelection, ch);
|
||||
}
|
||||
return new EditOperationResult(EditOperationType.Typing, commands, {
|
||||
shouldPushStackElementBefore: (prevEditOperationType !== EditOperationType.Typing),
|
||||
return new EditOperationResult(EditOperationType.TypingOther, commands, {
|
||||
shouldPushStackElementBefore: shouldPushStackElementBetween(prevEditOperationType, EditOperationType.TypingOther),
|
||||
shouldPushStackElementAfter: false
|
||||
});
|
||||
}
|
||||
@@ -636,7 +636,7 @@ export class TypeOperations {
|
||||
const selection = selections[i];
|
||||
commands[i] = new TypeWithAutoClosingCommand(selection, ch, insertOpenCharacter, autoClosingPairClose);
|
||||
}
|
||||
return new EditOperationResult(EditOperationType.Typing, commands, {
|
||||
return new EditOperationResult(EditOperationType.TypingOther, commands, {
|
||||
shouldPushStackElementBefore: true,
|
||||
shouldPushStackElementAfter: false
|
||||
});
|
||||
@@ -762,7 +762,7 @@ export class TypeOperations {
|
||||
let typeSelection = new Range(position.lineNumber, 1, position.lineNumber, position.column);
|
||||
|
||||
const command = new ReplaceCommand(typeSelection, typeText);
|
||||
return new EditOperationResult(EditOperationType.Typing, [command], {
|
||||
return new EditOperationResult(getTypingOperation(typeText, prevEditOperationType), [command], {
|
||||
shouldPushStackElementBefore: false,
|
||||
shouldPushStackElementAfter: true
|
||||
});
|
||||
@@ -803,7 +803,7 @@ export class TypeOperations {
|
||||
if (this._isAutoClosingOvertype(config, model, selections, autoClosedCharacters, ch)) {
|
||||
// Unfortunately, the close character is at this point "doubled", so we need to delete it...
|
||||
const commands = selections.map(s => new ReplaceCommand(new Range(s.positionLineNumber, s.positionColumn, s.positionLineNumber, s.positionColumn + 1), '', false));
|
||||
return new EditOperationResult(EditOperationType.Typing, commands, {
|
||||
return new EditOperationResult(EditOperationType.TypingOther, commands, {
|
||||
shouldPushStackElementBefore: true,
|
||||
shouldPushStackElementAfter: false
|
||||
});
|
||||
@@ -824,7 +824,7 @@ export class TypeOperations {
|
||||
for (let i = 0, len = selections.length; i < len; i++) {
|
||||
commands[i] = TypeOperations._enter(config, model, false, selections[i]);
|
||||
}
|
||||
return new EditOperationResult(EditOperationType.Typing, commands, {
|
||||
return new EditOperationResult(EditOperationType.TypingOther, commands, {
|
||||
shouldPushStackElementBefore: true,
|
||||
shouldPushStackElementAfter: false,
|
||||
});
|
||||
@@ -841,7 +841,7 @@ export class TypeOperations {
|
||||
}
|
||||
}
|
||||
if (!autoIndentFails) {
|
||||
return new EditOperationResult(EditOperationType.Typing, commands, {
|
||||
return new EditOperationResult(EditOperationType.TypingOther, commands, {
|
||||
shouldPushStackElementBefore: true,
|
||||
shouldPushStackElementAfter: false,
|
||||
});
|
||||
@@ -877,12 +877,10 @@ export class TypeOperations {
|
||||
for (let i = 0, len = selections.length; i < len; i++) {
|
||||
commands[i] = new ReplaceCommand(selections[i], ch);
|
||||
}
|
||||
let shouldPushStackElementBefore = (prevEditOperationType !== EditOperationType.Typing);
|
||||
if (ch === ' ') {
|
||||
shouldPushStackElementBefore = true;
|
||||
}
|
||||
return new EditOperationResult(EditOperationType.Typing, commands, {
|
||||
shouldPushStackElementBefore: shouldPushStackElementBefore,
|
||||
|
||||
const opType = getTypingOperation(ch, prevEditOperationType);
|
||||
return new EditOperationResult(opType, commands, {
|
||||
shouldPushStackElementBefore: shouldPushStackElementBetween(prevEditOperationType, opType),
|
||||
shouldPushStackElementAfter: false
|
||||
});
|
||||
}
|
||||
@@ -892,8 +890,9 @@ export class TypeOperations {
|
||||
for (let i = 0, len = selections.length; i < len; i++) {
|
||||
commands[i] = new ReplaceCommand(selections[i], str);
|
||||
}
|
||||
return new EditOperationResult(EditOperationType.Typing, commands, {
|
||||
shouldPushStackElementBefore: (prevEditOperationType !== EditOperationType.Typing),
|
||||
const opType = getTypingOperation(str, prevEditOperationType);
|
||||
return new EditOperationResult(opType, commands, {
|
||||
shouldPushStackElementBefore: shouldPushStackElementBetween(prevEditOperationType, opType),
|
||||
shouldPushStackElementAfter: false
|
||||
});
|
||||
}
|
||||
@@ -965,3 +964,40 @@ export class TypeWithAutoClosingCommand extends ReplaceCommandWithOffsetCursorSt
|
||||
return super.computeCursorState(model, helper);
|
||||
}
|
||||
}
|
||||
|
||||
function getTypingOperation(typedText: string, previousTypingOperation: EditOperationType): EditOperationType {
|
||||
if (typedText === ' ') {
|
||||
return previousTypingOperation === EditOperationType.TypingFirstSpace
|
||||
|| previousTypingOperation === EditOperationType.TypingConsecutiveSpace
|
||||
? EditOperationType.TypingConsecutiveSpace
|
||||
: EditOperationType.TypingFirstSpace;
|
||||
}
|
||||
|
||||
return EditOperationType.TypingOther;
|
||||
}
|
||||
|
||||
function shouldPushStackElementBetween(previousTypingOperation: EditOperationType, typingOperation: EditOperationType): boolean {
|
||||
if (isTypingOperation(previousTypingOperation) && !isTypingOperation(typingOperation)) {
|
||||
// Always set an undo stop before non-type operations
|
||||
return true;
|
||||
}
|
||||
if (previousTypingOperation === EditOperationType.TypingFirstSpace) {
|
||||
// `abc |d`: No undo stop
|
||||
// `abc |d`: Undo stop
|
||||
return false;
|
||||
}
|
||||
// Insert undo stop between different operation types
|
||||
return normalizeOperationType(previousTypingOperation) !== normalizeOperationType(typingOperation);
|
||||
}
|
||||
|
||||
function normalizeOperationType(type: EditOperationType): EditOperationType | 'space' {
|
||||
return (type === EditOperationType.TypingConsecutiveSpace || type === EditOperationType.TypingFirstSpace)
|
||||
? 'space'
|
||||
: type;
|
||||
}
|
||||
|
||||
function isTypingOperation(type: EditOperationType): boolean {
|
||||
return type === EditOperationType.TypingOther
|
||||
|| type === EditOperationType.TypingFirstSpace
|
||||
|| type === EditOperationType.TypingConsecutiveSpace;
|
||||
}
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { ColorId, LanguageId, StandardTokenType, TokenMetadata } from 'vs/editor/common/modes';
|
||||
import { ColorId, FontStyle, LanguageId, MetadataConsts, StandardTokenType, TokenMetadata } from 'vs/editor/common/modes';
|
||||
|
||||
export interface IViewLineTokens {
|
||||
equals(other: IViewLineTokens): boolean;
|
||||
@@ -22,6 +22,20 @@ export class LineTokens implements IViewLineTokens {
|
||||
private readonly _tokensCount: number;
|
||||
private readonly _text: string;
|
||||
|
||||
public static createEmpty(lineContent: string): LineTokens {
|
||||
const defaultMetadata = (
|
||||
(FontStyle.None << MetadataConsts.FONT_STYLE_OFFSET)
|
||||
| (ColorId.DefaultForeground << MetadataConsts.FOREGROUND_OFFSET)
|
||||
| (ColorId.DefaultBackground << MetadataConsts.BACKGROUND_OFFSET)
|
||||
) >>> 0;
|
||||
|
||||
const tokens = new Uint32Array(2);
|
||||
tokens[0] = lineContent.length;
|
||||
tokens[1] = defaultMetadata;
|
||||
|
||||
return new LineTokens(tokens, lineContent);
|
||||
}
|
||||
|
||||
constructor(tokens: Uint32Array, text: string) {
|
||||
this._tokens = tokens;
|
||||
this._tokensCount = (this._tokens.length >>> 1);
|
||||
|
||||
@@ -45,6 +45,10 @@ class LineSequence implements ISequence {
|
||||
return elements;
|
||||
}
|
||||
|
||||
public getStrictElement(index: number): string {
|
||||
return this.lines[index];
|
||||
}
|
||||
|
||||
public getStartLineNumber(i: number): number {
|
||||
return i + 1;
|
||||
}
|
||||
|
||||
@@ -503,7 +503,7 @@ export interface IEditor {
|
||||
* Change the decorations. All decorations added through this changeAccessor
|
||||
* will get the ownerId of the editor (meaning they will not show up in other
|
||||
* editors).
|
||||
* @see `ITextModel.changeDecorations`
|
||||
* @see {@link ITextModel.changeDecorations}
|
||||
* @internal
|
||||
*/
|
||||
changeDecorations(callback: (changeAccessor: IModelDecorationsChangeAccessor) => any): any;
|
||||
@@ -639,6 +639,7 @@ export interface IContentDecorationRenderOptions {
|
||||
textDecoration?: string;
|
||||
color?: string | ThemeColor;
|
||||
backgroundColor?: string | ThemeColor;
|
||||
opacity?: string;
|
||||
|
||||
margin?: string;
|
||||
padding?: string;
|
||||
|
||||
@@ -62,7 +62,7 @@ export namespace EditorContextKeys {
|
||||
export const hasReferenceProvider = new RawContextKey<boolean>('editorHasReferenceProvider', false, nls.localize('editorHasReferenceProvider', "Whether the editor has a reference provider"));
|
||||
export const hasRenameProvider = new RawContextKey<boolean>('editorHasRenameProvider', false, nls.localize('editorHasRenameProvider', "Whether the editor has a rename provider"));
|
||||
export const hasSignatureHelpProvider = new RawContextKey<boolean>('editorHasSignatureHelpProvider', false, nls.localize('editorHasSignatureHelpProvider', "Whether the editor has a signature help provider"));
|
||||
export const hasInlineHintsProvider = new RawContextKey<boolean>('editorHasInlineHintsProvider', false, nls.localize('editorHasInlineHintsProvider', "Whether the editor has an inline hints provider"));
|
||||
export const hasInlayHintsProvider = new RawContextKey<boolean>('editorHasInlayHintsProvider', false, nls.localize('editorHasInlayHintsProvider', "Whether the editor has an inline hints provider"));
|
||||
|
||||
// -- mode context keys: formatting
|
||||
export const hasDocumentFormattingProvider = new RawContextKey<boolean>('editorHasDocumentFormattingProvider', false, nls.localize('editorHasDocumentFormattingProvider', "Whether the editor has a document formatting provider"));
|
||||
|
||||
@@ -73,6 +73,11 @@ export interface IModelDecorationMinimapOptions extends IDecorationOptions {
|
||||
* Options for a model decoration.
|
||||
*/
|
||||
export interface IModelDecorationOptions {
|
||||
/**
|
||||
* A debug description that can be used for inspecting model decorations.
|
||||
* @internal
|
||||
*/
|
||||
description: string;
|
||||
/**
|
||||
* Customize the growing behavior of the decoration when typing at the edges of the decoration.
|
||||
* Defaults to TrackedRangeStickiness.AlwaysGrowsWhenTypingAtEdges
|
||||
@@ -1220,7 +1225,6 @@ export interface ITextModel {
|
||||
/**
|
||||
* An event emitted when the model has been attached to the first editor or detached from the last editor.
|
||||
* @event
|
||||
* @internal
|
||||
*/
|
||||
onDidChangeAttached(listener: () => void): IDisposable;
|
||||
/**
|
||||
@@ -1247,7 +1251,6 @@ export interface ITextModel {
|
||||
|
||||
/**
|
||||
* Returns if this model is attached to an editor or not.
|
||||
* @internal
|
||||
*/
|
||||
isAttachedToEditor(): boolean;
|
||||
|
||||
@@ -1256,6 +1259,33 @@ export interface ITextModel {
|
||||
* @internal
|
||||
*/
|
||||
getAttachedEditorCount(): number;
|
||||
|
||||
/**
|
||||
* Among all positions that are projected to the same position in the underlying text model as
|
||||
* the given position, select a unique position as indicated by the affinity.
|
||||
* @internal
|
||||
*/
|
||||
normalizePosition(position: Position, affinity: PositionNormalizationAffinity): Position;
|
||||
|
||||
/**
|
||||
* Gets the column at which indentation stops at a given line.
|
||||
* @internal
|
||||
*/
|
||||
getLineIndentColumn(lineNumber: number): number;
|
||||
}
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
export const enum PositionNormalizationAffinity {
|
||||
/**
|
||||
* Prefers the left most position.
|
||||
*/
|
||||
Left = 0,
|
||||
/**
|
||||
* Prefers the right most position.
|
||||
*/
|
||||
Right = 1,
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -3028,6 +3028,30 @@ export class TextModel extends Disposable implements model.ITextModel {
|
||||
}
|
||||
|
||||
//#endregion
|
||||
normalizePosition(position: Position, affinity: model.PositionNormalizationAffinity): Position {
|
||||
return position;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the column at which indentation stops at a given line.
|
||||
* @internal
|
||||
*/
|
||||
public getLineIndentColumn(lineNumber: number): number {
|
||||
// Columns start with 1.
|
||||
return indentOfLine(this.getLineContent(lineNumber)) + 1;
|
||||
}
|
||||
}
|
||||
|
||||
function indentOfLine(line: string): number {
|
||||
let indent = 0;
|
||||
for (const c of line) {
|
||||
if (c === ' ' || c === '\t') {
|
||||
indent++;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
return indent;
|
||||
}
|
||||
|
||||
//#region Decorations
|
||||
@@ -3205,6 +3229,7 @@ export class ModelDecorationOptions implements model.IModelDecorationOptions {
|
||||
return new ModelDecorationOptions(options);
|
||||
}
|
||||
|
||||
readonly description: string;
|
||||
readonly stickiness: model.TrackedRangeStickiness;
|
||||
readonly zIndex: number;
|
||||
readonly className: string | null;
|
||||
@@ -3225,6 +3250,7 @@ export class ModelDecorationOptions implements model.IModelDecorationOptions {
|
||||
readonly afterContentClassName: string | null;
|
||||
|
||||
private constructor(options: model.IModelDecorationOptions) {
|
||||
this.description = options.description;
|
||||
this.stickiness = options.stickiness || model.TrackedRangeStickiness.AlwaysGrowsWhenTypingAtEdges;
|
||||
this.zIndex = options.zIndex || 0;
|
||||
this.className = options.className ? cleanClassName(options.className) : null;
|
||||
@@ -3245,16 +3271,16 @@ export class ModelDecorationOptions implements model.IModelDecorationOptions {
|
||||
this.afterContentClassName = options.afterContentClassName ? cleanClassName(options.afterContentClassName) : null;
|
||||
}
|
||||
}
|
||||
ModelDecorationOptions.EMPTY = ModelDecorationOptions.register({});
|
||||
ModelDecorationOptions.EMPTY = ModelDecorationOptions.register({ description: 'empty' });
|
||||
|
||||
/**
|
||||
* The order carefully matches the values of the enum.
|
||||
*/
|
||||
const TRACKED_RANGE_OPTIONS = [
|
||||
ModelDecorationOptions.register({ stickiness: model.TrackedRangeStickiness.AlwaysGrowsWhenTypingAtEdges }),
|
||||
ModelDecorationOptions.register({ stickiness: model.TrackedRangeStickiness.NeverGrowsWhenTypingAtEdges }),
|
||||
ModelDecorationOptions.register({ stickiness: model.TrackedRangeStickiness.GrowsOnlyWhenTypingBefore }),
|
||||
ModelDecorationOptions.register({ stickiness: model.TrackedRangeStickiness.GrowsOnlyWhenTypingAfter }),
|
||||
ModelDecorationOptions.register({ description: 'tracked-range-always-grows-when-typing-at-edges', stickiness: model.TrackedRangeStickiness.AlwaysGrowsWhenTypingAtEdges }),
|
||||
ModelDecorationOptions.register({ description: 'tracked-range-never-grows-when-typing-at-edges', stickiness: model.TrackedRangeStickiness.NeverGrowsWhenTypingAtEdges }),
|
||||
ModelDecorationOptions.register({ description: 'tracked-range-grows-only-when-typing-before', stickiness: model.TrackedRangeStickiness.GrowsOnlyWhenTypingBefore }),
|
||||
ModelDecorationOptions.register({ description: 'tracked-range-grows-only-when-typing-after', stickiness: model.TrackedRangeStickiness.GrowsOnlyWhenTypingAfter }),
|
||||
];
|
||||
|
||||
function _normalizeOptions(options: model.IModelDecorationOptions): ModelDecorationOptions {
|
||||
|
||||
@@ -9,7 +9,7 @@ import { Event } from 'vs/base/common/event';
|
||||
import { IMarkdownString } from 'vs/base/common/htmlContent';
|
||||
import { IDisposable } from 'vs/base/common/lifecycle';
|
||||
import { URI, UriComponents } from 'vs/base/common/uri';
|
||||
import { Position } from 'vs/editor/common/core/position';
|
||||
import { IPosition, Position } from 'vs/editor/common/core/position';
|
||||
import { IRange, Range } from 'vs/editor/common/core/range';
|
||||
import { Selection } from 'vs/editor/common/core/selection';
|
||||
import { TokenizationResult, TokenizationResult2 } from 'vs/editor/common/core/token';
|
||||
@@ -227,7 +227,7 @@ export interface IState {
|
||||
}
|
||||
|
||||
/**
|
||||
* A provider result represents the values a provider, like the [`HoverProvider`](#HoverProvider),
|
||||
* A provider result represents the values a provider, like the {@link HoverProvider},
|
||||
* may return. For once this is the actual result type `T`, like `Hover`, or a thenable that resolves
|
||||
* to that type `T`. In addition, `null` and `undefined` can be returned - either directly or from a
|
||||
* thenable.
|
||||
@@ -557,13 +557,13 @@ export interface CompletionItem {
|
||||
documentation?: string | IMarkdownString;
|
||||
/**
|
||||
* A string that should be used when comparing this item
|
||||
* with other items. When `falsy` the [label](#CompletionItem.label)
|
||||
* with other items. When `falsy` the {@link CompletionItem.label label}
|
||||
* is used.
|
||||
*/
|
||||
sortText?: string;
|
||||
/**
|
||||
* A string that should be used when filtering a set of
|
||||
* completion items. When `falsy` the [label](#CompletionItem.label)
|
||||
* completion items. When `falsy` the {@link CompletionItem.label label}
|
||||
* is used.
|
||||
*/
|
||||
filterText?: string;
|
||||
@@ -587,11 +587,11 @@ export interface CompletionItem {
|
||||
/**
|
||||
* A range of text that should be replaced by this completion item.
|
||||
*
|
||||
* Defaults to a range from the start of the [current word](#TextDocument.getWordRangeAtPosition) to the
|
||||
* Defaults to a range from the start of the {@link TextDocument.getWordRangeAtPosition current word} to the
|
||||
* current position.
|
||||
*
|
||||
* *Note:* The range must be a [single line](#Range.isSingleLine) and it must
|
||||
* [contain](#Range.contains) the position at which completion has been [requested](#CompletionItemProvider.provideCompletionItems).
|
||||
* *Note:* The range must be a {@link Range.isSingleLine single line} and it must
|
||||
* {@link Range.contains contain} the position at which completion has been {@link CompletionItemProvider.provideCompletionItems requested}.
|
||||
*/
|
||||
range: IRange | { insert: IRange, replace: IRange };
|
||||
/**
|
||||
@@ -638,7 +638,7 @@ export const enum CompletionTriggerKind {
|
||||
}
|
||||
/**
|
||||
* Contains additional information about the context in which
|
||||
* [completion provider](#CompletionItemProvider.provideCompletionItems) is triggered.
|
||||
* {@link CompletionItemProvider.provideCompletionItems completion provider} is triggered.
|
||||
*/
|
||||
export interface CompletionContext {
|
||||
/**
|
||||
@@ -658,10 +658,10 @@ export interface CompletionContext {
|
||||
*
|
||||
* When computing *complete* completion items is expensive, providers can optionally implement
|
||||
* the `resolveCompletionItem`-function. In that case it is enough to return completion
|
||||
* items with a [label](#CompletionItem.label) from the
|
||||
* [provideCompletionItems](#CompletionItemProvider.provideCompletionItems)-function. Subsequently,
|
||||
* items with a {@link CompletionItem.label label} from the
|
||||
* {@link CompletionItemProvider.provideCompletionItems provideCompletionItems}-function. Subsequently,
|
||||
* when a completion item is shown in the UI and gains focus this provider is asked to resolve
|
||||
* the item, like adding [doc-comment](#CompletionItem.documentation) or [details](#CompletionItem.detail).
|
||||
* the item, like adding {@link CompletionItem.documentation doc-comment} or {@link CompletionItem.detail details}.
|
||||
*/
|
||||
export interface CompletionItemProvider {
|
||||
|
||||
@@ -677,14 +677,73 @@ export interface CompletionItemProvider {
|
||||
provideCompletionItems(model: model.ITextModel, position: Position, context: CompletionContext, token: CancellationToken): ProviderResult<CompletionList>;
|
||||
|
||||
/**
|
||||
* Given a completion item fill in more data, like [doc-comment](#CompletionItem.documentation)
|
||||
* or [details](#CompletionItem.detail).
|
||||
* Given a completion item fill in more data, like {@link CompletionItem.documentation doc-comment}
|
||||
* or {@link CompletionItem.detail details}.
|
||||
*
|
||||
* The editor will only resolve a completion item once.
|
||||
*/
|
||||
resolveCompletionItem?(item: CompletionItem, token: CancellationToken): ProviderResult<CompletionItem>;
|
||||
}
|
||||
|
||||
/**
|
||||
* How an {@link InlineCompletionsProvider inline completion provider} was triggered.
|
||||
*/
|
||||
export enum InlineCompletionTriggerKind {
|
||||
/**
|
||||
* Completion was triggered automatically while editing.
|
||||
* It is sufficient to return a single completion item in this case.
|
||||
*/
|
||||
Automatic = 0,
|
||||
|
||||
/**
|
||||
* Completion was triggered explicitly by a user gesture.
|
||||
* Return multiple completion items to enable cycling through them.
|
||||
*/
|
||||
Explicit = 1,
|
||||
}
|
||||
|
||||
export interface InlineCompletionContext {
|
||||
/**
|
||||
* How the completion was triggered.
|
||||
*/
|
||||
readonly triggerKind: InlineCompletionTriggerKind;
|
||||
}
|
||||
|
||||
export interface InlineCompletion {
|
||||
/**
|
||||
* The text to insert.
|
||||
* If the text contains a line break, the range must end at the end of a line.
|
||||
* If existing text should be replaced, the existing text must be a prefix of the text to insert.
|
||||
*/
|
||||
readonly text: string;
|
||||
|
||||
/**
|
||||
* The range to replace.
|
||||
* Must begin and end on the same line.
|
||||
*/
|
||||
readonly range?: IRange;
|
||||
|
||||
readonly command?: Command;
|
||||
}
|
||||
|
||||
export interface InlineCompletions<TItem extends InlineCompletion = InlineCompletion> {
|
||||
readonly items: readonly TItem[];
|
||||
}
|
||||
|
||||
export interface InlineCompletionsProvider<T extends InlineCompletions = InlineCompletions> {
|
||||
provideInlineCompletions(model: model.ITextModel, position: Position, context: InlineCompletionContext, token: CancellationToken): ProviderResult<T>;
|
||||
|
||||
/**
|
||||
* Will be called when an item is shown.
|
||||
*/
|
||||
handleItemDidShow?(completions: T, item: T['items'][number]): void;
|
||||
|
||||
/**
|
||||
* Will be called when a completions list is no longer in use and can be garbage-collected.
|
||||
*/
|
||||
freeInlineCompletions(completions: T): void;
|
||||
}
|
||||
|
||||
export interface CodeAction {
|
||||
title: string;
|
||||
command?: Command;
|
||||
@@ -870,7 +929,7 @@ export interface DocumentHighlight {
|
||||
*/
|
||||
range: IRange;
|
||||
/**
|
||||
* The highlight kind, default is [text](#DocumentHighlightKind.Text).
|
||||
* The highlight kind, default is {@link DocumentHighlightKind.Text text}.
|
||||
*/
|
||||
kind?: DocumentHighlightKind;
|
||||
}
|
||||
@@ -1323,12 +1382,12 @@ export interface IColorPresentation {
|
||||
*/
|
||||
label: string;
|
||||
/**
|
||||
* An [edit](#TextEdit) which is applied to a document when selecting
|
||||
* An {@link TextEdit edit} which is applied to a document when selecting
|
||||
* this presentation for the color.
|
||||
*/
|
||||
textEdit?: TextEdit;
|
||||
/**
|
||||
* An optional array of additional [text edits](#TextEdit) that are applied when
|
||||
* An optional array of additional {@link TextEdit text edits} that are applied when
|
||||
* selecting this color presentation.
|
||||
*/
|
||||
additionalTextEdits?: TextEdit[];
|
||||
@@ -1406,10 +1465,10 @@ export interface FoldingRange {
|
||||
end: number;
|
||||
|
||||
/**
|
||||
* Describes the [Kind](#FoldingRangeKind) of the folding range such as [Comment](#FoldingRangeKind.Comment) or
|
||||
* [Region](#FoldingRangeKind.Region). The kind is used to categorize folding ranges and used by commands
|
||||
* Describes the {@link FoldingRangeKind Kind} of the folding range such as {@link FoldingRangeKind.Comment Comment} or
|
||||
* {@link FoldingRangeKind.Region Region}. The kind is used to categorize folding ranges and used by commands
|
||||
* like 'Fold all comments'. See
|
||||
* [FoldingRangeKind](#FoldingRangeKind) for an enumeration of standardized kinds.
|
||||
* {@link FoldingRangeKind} for an enumeration of standardized kinds.
|
||||
*/
|
||||
kind?: FoldingRangeKind;
|
||||
}
|
||||
@@ -1429,7 +1488,7 @@ export class FoldingRangeKind {
|
||||
static readonly Region = new FoldingRangeKind('region');
|
||||
|
||||
/**
|
||||
* Creates a new [FoldingRangeKind](#FoldingRangeKind).
|
||||
* Creates a new {@link FoldingRangeKind}.
|
||||
*
|
||||
* @param value of the kind.
|
||||
*/
|
||||
@@ -1701,24 +1760,23 @@ export interface CodeLensProvider {
|
||||
}
|
||||
|
||||
|
||||
export enum InlineHintKind {
|
||||
export enum InlayHintKind {
|
||||
Other = 0,
|
||||
Type = 1,
|
||||
Parameter = 2,
|
||||
}
|
||||
|
||||
export interface InlineHint {
|
||||
export interface InlayHint {
|
||||
text: string;
|
||||
range: IRange;
|
||||
kind: InlineHintKind;
|
||||
description?: string | IMarkdownString;
|
||||
position: IPosition;
|
||||
kind: InlayHintKind;
|
||||
whitespaceBefore?: boolean;
|
||||
whitespaceAfter?: boolean;
|
||||
}
|
||||
|
||||
export interface InlineHintsProvider {
|
||||
onDidChangeInlineHints?: Event<void> | undefined;
|
||||
provideInlineHints(model: model.ITextModel, range: Range, token: CancellationToken): ProviderResult<InlineHint[]>;
|
||||
export interface InlayHintsProvider {
|
||||
onDidChangeInlayHints?: Event<void> | undefined;
|
||||
provideInlayHints(model: model.ITextModel, range: Range, token: CancellationToken): ProviderResult<InlayHint[]>;
|
||||
}
|
||||
|
||||
export interface SemanticTokensLegend {
|
||||
@@ -1771,6 +1829,11 @@ export const RenameProviderRegistry = new LanguageFeatureRegistry<RenameProvider
|
||||
*/
|
||||
export const CompletionProviderRegistry = new LanguageFeatureRegistry<CompletionItemProvider>();
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
export const InlineCompletionsProviderRegistry = new LanguageFeatureRegistry<InlineCompletionsProvider>();
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
@@ -1834,7 +1897,7 @@ export const CodeLensProviderRegistry = new LanguageFeatureRegistry<CodeLensProv
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
export const InlineHintsProviderRegistry = new LanguageFeatureRegistry<InlineHintsProvider>();
|
||||
export const InlayHintsProviderRegistry = new LanguageFeatureRegistry<InlayHintsProvider>();
|
||||
|
||||
/**
|
||||
* @internal
|
||||
|
||||
@@ -154,7 +154,7 @@ function getClassifier(): CharacterClassifier<CharacterClass> {
|
||||
if (_classifier === null) {
|
||||
_classifier = new CharacterClassifier<CharacterClass>(CharacterClass.None);
|
||||
|
||||
const FORCE_TERMINATION_CHARACTERS = ' \t<>\'\"、。。、,.:;‘“〈《「『【〔([{「」}])〕】』」》〉”’`~…';
|
||||
const FORCE_TERMINATION_CHARACTERS = ' \t<>\'\"、。。、,.:;‘〈「『〔([{「」}])〕』」〉’`~…';
|
||||
for (let i = 0; i < FORCE_TERMINATION_CHARACTERS.length; i++) {
|
||||
_classifier.set(FORCE_TERMINATION_CHARACTERS.charCodeAt(i), CharacterClass.ForceTermination);
|
||||
}
|
||||
|
||||
@@ -64,7 +64,12 @@ export class OnEnterSupport {
|
||||
reg: rule.previousLineText,
|
||||
text: previousLineText
|
||||
}].every((obj): boolean => {
|
||||
return obj.reg ? obj.reg.test(obj.text) : true;
|
||||
if (!obj.reg) {
|
||||
return true;
|
||||
}
|
||||
|
||||
obj.reg.lastIndex = 0; // To disable the effect of the "g" flag.
|
||||
return obj.reg.test(obj.text);
|
||||
});
|
||||
|
||||
if (regResult) {
|
||||
|
||||
@@ -239,6 +239,7 @@ export class MarkerDecorationsService extends Disposable implements IMarkerDecor
|
||||
}
|
||||
|
||||
return {
|
||||
description: 'marker-decoration',
|
||||
stickiness: TrackedRangeStickiness.NeverGrowsWhenTypingAtEdges,
|
||||
className,
|
||||
showIfCollapsed: true,
|
||||
|
||||
@@ -219,82 +219,84 @@ export enum EditorOption {
|
||||
highlightActiveIndentGuide = 49,
|
||||
hover = 50,
|
||||
inDiffEditor = 51,
|
||||
letterSpacing = 52,
|
||||
lightbulb = 53,
|
||||
lineDecorationsWidth = 54,
|
||||
lineHeight = 55,
|
||||
lineNumbers = 56,
|
||||
lineNumbersMinChars = 57,
|
||||
linkedEditing = 58,
|
||||
links = 59,
|
||||
matchBrackets = 60,
|
||||
minimap = 61,
|
||||
mouseStyle = 62,
|
||||
mouseWheelScrollSensitivity = 63,
|
||||
mouseWheelZoom = 64,
|
||||
multiCursorMergeOverlapping = 65,
|
||||
multiCursorModifier = 66,
|
||||
multiCursorPaste = 67,
|
||||
occurrencesHighlight = 68,
|
||||
overviewRulerBorder = 69,
|
||||
overviewRulerLanes = 70,
|
||||
padding = 71,
|
||||
parameterHints = 72,
|
||||
peekWidgetDefaultFocus = 73,
|
||||
definitionLinkOpensInPeek = 74,
|
||||
quickSuggestions = 75,
|
||||
quickSuggestionsDelay = 76,
|
||||
readOnly = 77,
|
||||
renameOnType = 78,
|
||||
renderControlCharacters = 79,
|
||||
renderIndentGuides = 80,
|
||||
renderFinalNewline = 81,
|
||||
renderLineHighlight = 82,
|
||||
renderLineHighlightOnlyWhenFocus = 83,
|
||||
renderValidationDecorations = 84,
|
||||
renderWhitespace = 85,
|
||||
revealHorizontalRightPadding = 86,
|
||||
roundedSelection = 87,
|
||||
rulers = 88,
|
||||
scrollbar = 89,
|
||||
scrollBeyondLastColumn = 90,
|
||||
scrollBeyondLastLine = 91,
|
||||
scrollPredominantAxis = 92,
|
||||
selectionClipboard = 93,
|
||||
selectionHighlight = 94,
|
||||
selectOnLineNumbers = 95,
|
||||
showFoldingControls = 96,
|
||||
showUnused = 97,
|
||||
snippetSuggestions = 98,
|
||||
smartSelect = 99,
|
||||
smoothScrolling = 100,
|
||||
stickyTabStops = 101,
|
||||
stopRenderingLineAfter = 102,
|
||||
suggest = 103,
|
||||
suggestFontSize = 104,
|
||||
suggestLineHeight = 105,
|
||||
suggestOnTriggerCharacters = 106,
|
||||
suggestSelection = 107,
|
||||
tabCompletion = 108,
|
||||
tabIndex = 109,
|
||||
unusualLineTerminators = 110,
|
||||
useTabStops = 111,
|
||||
wordSeparators = 112,
|
||||
wordWrap = 113,
|
||||
wordWrapBreakAfterCharacters = 114,
|
||||
wordWrapBreakBeforeCharacters = 115,
|
||||
wordWrapColumn = 116,
|
||||
wordWrapOverride1 = 117,
|
||||
wordWrapOverride2 = 118,
|
||||
wrappingIndent = 119,
|
||||
wrappingStrategy = 120,
|
||||
showDeprecated = 121,
|
||||
inlineHints = 122,
|
||||
editorClassName = 123,
|
||||
pixelRatio = 124,
|
||||
tabFocusMode = 125,
|
||||
layoutInfo = 126,
|
||||
wrappingInfo = 127
|
||||
inlineSuggest = 52,
|
||||
letterSpacing = 53,
|
||||
lightbulb = 54,
|
||||
lineDecorationsWidth = 55,
|
||||
lineHeight = 56,
|
||||
lineNumbers = 57,
|
||||
lineNumbersMinChars = 58,
|
||||
linkedEditing = 59,
|
||||
links = 60,
|
||||
matchBrackets = 61,
|
||||
minimap = 62,
|
||||
mouseStyle = 63,
|
||||
mouseWheelScrollSensitivity = 64,
|
||||
mouseWheelZoom = 65,
|
||||
multiCursorMergeOverlapping = 66,
|
||||
multiCursorModifier = 67,
|
||||
multiCursorPaste = 68,
|
||||
occurrencesHighlight = 69,
|
||||
overviewRulerBorder = 70,
|
||||
overviewRulerLanes = 71,
|
||||
padding = 72,
|
||||
parameterHints = 73,
|
||||
peekWidgetDefaultFocus = 74,
|
||||
definitionLinkOpensInPeek = 75,
|
||||
quickSuggestions = 76,
|
||||
quickSuggestionsDelay = 77,
|
||||
readOnly = 78,
|
||||
renameOnType = 79,
|
||||
renderControlCharacters = 80,
|
||||
renderIndentGuides = 81,
|
||||
renderFinalNewline = 82,
|
||||
renderLineHighlight = 83,
|
||||
renderLineHighlightOnlyWhenFocus = 84,
|
||||
renderValidationDecorations = 85,
|
||||
renderWhitespace = 86,
|
||||
revealHorizontalRightPadding = 87,
|
||||
roundedSelection = 88,
|
||||
rulers = 89,
|
||||
scrollbar = 90,
|
||||
scrollBeyondLastColumn = 91,
|
||||
scrollBeyondLastLine = 92,
|
||||
scrollPredominantAxis = 93,
|
||||
selectionClipboard = 94,
|
||||
selectionHighlight = 95,
|
||||
selectOnLineNumbers = 96,
|
||||
showFoldingControls = 97,
|
||||
showUnused = 98,
|
||||
snippetSuggestions = 99,
|
||||
smartSelect = 100,
|
||||
smoothScrolling = 101,
|
||||
stickyTabStops = 102,
|
||||
stopRenderingLineAfter = 103,
|
||||
suggest = 104,
|
||||
suggestFontSize = 105,
|
||||
suggestLineHeight = 106,
|
||||
suggestOnTriggerCharacters = 107,
|
||||
suggestSelection = 108,
|
||||
tabCompletion = 109,
|
||||
tabIndex = 110,
|
||||
unusualLineTerminators = 111,
|
||||
useShadowDOM = 112,
|
||||
useTabStops = 113,
|
||||
wordSeparators = 114,
|
||||
wordWrap = 115,
|
||||
wordWrapBreakAfterCharacters = 116,
|
||||
wordWrapBreakBeforeCharacters = 117,
|
||||
wordWrapColumn = 118,
|
||||
wordWrapOverride1 = 119,
|
||||
wordWrapOverride2 = 120,
|
||||
wrappingIndent = 121,
|
||||
wrappingStrategy = 122,
|
||||
showDeprecated = 123,
|
||||
inlayHints = 124,
|
||||
editorClassName = 125,
|
||||
pixelRatio = 126,
|
||||
tabFocusMode = 127,
|
||||
layoutInfo = 128,
|
||||
wrappingInfo = 129
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -353,12 +355,28 @@ export enum IndentAction {
|
||||
Outdent = 3
|
||||
}
|
||||
|
||||
export enum InlineHintKind {
|
||||
export enum InlayHintKind {
|
||||
Other = 0,
|
||||
Type = 1,
|
||||
Parameter = 2
|
||||
}
|
||||
|
||||
/**
|
||||
* How an {@link InlineCompletionsProvider inline completion provider} was triggered.
|
||||
*/
|
||||
export enum InlineCompletionTriggerKind {
|
||||
/**
|
||||
* Completion was triggered automatically while editing.
|
||||
* It is sufficient to return a single completion item in this case.
|
||||
*/
|
||||
Automatic = 0,
|
||||
/**
|
||||
* Completion was triggered explicitly by a user gesture.
|
||||
* Return multiple completion items to enable cycling through them.
|
||||
*/
|
||||
Explicit = 1
|
||||
}
|
||||
|
||||
/**
|
||||
* Virtual Key Codes, the value does not hold any inherent meaning.
|
||||
* Inspired somewhat from https://msdn.microsoft.com/en-us/library/windows/desktop/dd375731(v=vs.85).aspx
|
||||
@@ -823,4 +841,4 @@ export enum WrappingIndent {
|
||||
* DeepIndent => wrapped lines get +2 indentation toward the parent.
|
||||
*/
|
||||
DeepIndent = 3
|
||||
}
|
||||
}
|
||||
|
||||
@@ -43,6 +43,9 @@ export const editorGutter = registerColor('editorGutter.background', { dark: edi
|
||||
export const editorUnnecessaryCodeBorder = registerColor('editorUnnecessaryCode.border', { dark: null, light: null, hc: Color.fromHex('#fff').transparent(0.8) }, nls.localize('unnecessaryCodeBorder', 'Border color of unnecessary (unused) source code in the editor.'));
|
||||
export const editorUnnecessaryCodeOpacity = registerColor('editorUnnecessaryCode.opacity', { dark: Color.fromHex('#000a'), light: Color.fromHex('#0007'), hc: null }, nls.localize('unnecessaryCodeOpacity', 'Opacity of unnecessary (unused) source code in the editor. For example, "#000000c0" will render the code with 75% opacity. For high contrast themes, use the \'editorUnnecessaryCode.border\' theme color to underline unnecessary code instead of fading it out.'));
|
||||
|
||||
export const ghostTextBorder = registerColor('editorGhostText.border', { dark: null, light: null, hc: Color.fromHex('#fff').transparent(0.8) }, nls.localize('editorGhostTextBorder', 'Border color of ghost text in the editor.'));
|
||||
export const ghostTextForeground = registerColor('editorGhostText.foreground', { dark: Color.fromHex('#ffffff56'), light: Color.fromHex('#0007'), hc: null }, nls.localize('editorGhostTextForeground', 'Foreground color of the ghost text in the editor.'));
|
||||
|
||||
const rulerRangeDefault = new Color(new RGBA(0, 122, 204, 0.6));
|
||||
export const overviewRulerRangeHighlight = registerColor('editorOverviewRuler.rangeHighlightForeground', { dark: rulerRangeDefault, light: rulerRangeDefault, hc: rulerRangeDefault }, nls.localize('overviewRulerRangeHighlight', 'Overview ruler marker color for range highlights. The color must not be opaque so as not to hide underlying decorations.'), true);
|
||||
export const overviewRulerError = registerColor('editorOverviewRuler.errorForeground', { dark: new Color(new RGBA(255, 18, 18, 0.7)), light: new Color(new RGBA(255, 18, 18, 0.7)), hc: new Color(new RGBA(255, 50, 50, 1)) }, nls.localize('overviewRuleError', 'Overview ruler marker color for errors.'));
|
||||
|
||||
@@ -47,6 +47,10 @@ class LinePart {
|
||||
public isWhitespace(): boolean {
|
||||
return (this.metadata & LinePartMetadata.IS_WHITESPACE_MASK ? true : false);
|
||||
}
|
||||
|
||||
public isPseudoAfter(): boolean {
|
||||
return (this.metadata & LinePartMetadata.PSEUDO_AFTER_MASK ? true : false);
|
||||
}
|
||||
}
|
||||
|
||||
export class LineRange {
|
||||
@@ -213,16 +217,23 @@ export const enum CharacterMappingConstants {
|
||||
PART_INDEX_OFFSET = 16
|
||||
}
|
||||
|
||||
export class DomPosition {
|
||||
constructor(
|
||||
public readonly partIndex: number,
|
||||
public readonly charIndex: number
|
||||
) { }
|
||||
}
|
||||
|
||||
/**
|
||||
* Provides a both direction mapping between a line's character and its rendered position.
|
||||
*/
|
||||
export class CharacterMapping {
|
||||
|
||||
public static getPartIndex(partData: number): number {
|
||||
private static getPartIndex(partData: number): number {
|
||||
return (partData & CharacterMappingConstants.PART_INDEX_MASK) >>> CharacterMappingConstants.PART_INDEX_OFFSET;
|
||||
}
|
||||
|
||||
public static getCharIndex(partData: number): number {
|
||||
private static getCharIndex(partData: number): number {
|
||||
return (partData & CharacterMappingConstants.CHAR_INDEX_MASK) >>> CharacterMappingConstants.CHAR_INDEX_OFFSET;
|
||||
}
|
||||
|
||||
@@ -236,20 +247,24 @@ export class CharacterMapping {
|
||||
this._absoluteOffsets = new Uint32Array(this.length);
|
||||
}
|
||||
|
||||
public setPartData(charOffset: number, partIndex: number, charIndex: number, partAbsoluteOffset: number): void {
|
||||
let partData = (
|
||||
public setColumnInfo(column: number, partIndex: number, charIndex: number, partAbsoluteOffset: number): void {
|
||||
const partData = (
|
||||
(partIndex << CharacterMappingConstants.PART_INDEX_OFFSET)
|
||||
| (charIndex << CharacterMappingConstants.CHAR_INDEX_OFFSET)
|
||||
) >>> 0;
|
||||
this._data[charOffset] = partData;
|
||||
this._absoluteOffsets[charOffset] = partAbsoluteOffset + charIndex;
|
||||
this._data[column - 1] = partData;
|
||||
this._absoluteOffsets[column - 1] = partAbsoluteOffset + charIndex;
|
||||
}
|
||||
|
||||
public getAbsoluteOffsets(): Uint32Array {
|
||||
return this._absoluteOffsets;
|
||||
public getAbsoluteOffset(column: number): number {
|
||||
if (this._absoluteOffsets.length === 0) {
|
||||
// No characters on this line
|
||||
return 0;
|
||||
}
|
||||
return this._absoluteOffsets[column - 1];
|
||||
}
|
||||
|
||||
public charOffsetToPartData(charOffset: number): number {
|
||||
private charOffsetToPartData(charOffset: number): number {
|
||||
if (this.length === 0) {
|
||||
return 0;
|
||||
}
|
||||
@@ -262,7 +277,19 @@ export class CharacterMapping {
|
||||
return this._data[charOffset];
|
||||
}
|
||||
|
||||
public partDataToCharOffset(partIndex: number, partLength: number, charIndex: number): number {
|
||||
public getDomPosition(column: number): DomPosition {
|
||||
const partData = this.charOffsetToPartData(column - 1);
|
||||
const partIndex = CharacterMapping.getPartIndex(partData);
|
||||
const charIndex = CharacterMapping.getCharIndex(partData);
|
||||
return new DomPosition(partIndex, charIndex);
|
||||
}
|
||||
|
||||
public getColumn(domPosition: DomPosition, partLength: number): number {
|
||||
const charOffset = this.partDataToCharOffset(domPosition.partIndex, partLength, domPosition.charIndex);
|
||||
return charOffset + 1;
|
||||
}
|
||||
|
||||
private partDataToCharOffset(partIndex: number, partLength: number, charIndex: number): number {
|
||||
if (this.length === 0) {
|
||||
return 0;
|
||||
}
|
||||
@@ -373,7 +400,7 @@ export function renderViewLine(input: RenderLineInput, sb: IStringBuilder): Rend
|
||||
sb.appendASCIIString(`</span>`);
|
||||
|
||||
const characterMapping = new CharacterMapping(1, beforeCount + afterCount);
|
||||
characterMapping.setPartData(0, beforeCount, 0, 0);
|
||||
characterMapping.setColumnInfo(1, beforeCount, 0, 0);
|
||||
|
||||
return new RenderLineOutput(
|
||||
characterMapping,
|
||||
@@ -792,14 +819,11 @@ function _applyInlineDecorations(lineContent: string, len: number, tokens: LineP
|
||||
|
||||
const lastTokenEndIndex = tokens[tokens.length - 1].endIndex;
|
||||
if (lineDecorationIndex < lineDecorationsLen && lineDecorations[lineDecorationIndex].startOffset === lastTokenEndIndex) {
|
||||
let classNames: string[] = [];
|
||||
let metadata = 0;
|
||||
while (lineDecorationIndex < lineDecorationsLen && lineDecorations[lineDecorationIndex].startOffset === lastTokenEndIndex) {
|
||||
classNames.push(lineDecorations[lineDecorationIndex].className);
|
||||
metadata |= lineDecorations[lineDecorationIndex].metadata;
|
||||
const lineDecoration = lineDecorations[lineDecorationIndex];
|
||||
result[resultLen++] = new LinePart(lastResultEndIndex, lineDecoration.className, lineDecoration.metadata);
|
||||
lineDecorationIndex++;
|
||||
}
|
||||
result[resultLen++] = new LinePart(lastResultEndIndex, classNames.join(' '), metadata);
|
||||
}
|
||||
|
||||
return result;
|
||||
@@ -827,6 +851,7 @@ function _renderLine(input: ResolvedRenderLineInput, sb: IStringBuilder): Render
|
||||
const renderControlCharacters = input.renderControlCharacters;
|
||||
|
||||
const characterMapping = new CharacterMapping(len + 1, parts.length);
|
||||
let lastCharacterMappingDefined = false;
|
||||
|
||||
let charIndex = 0;
|
||||
let visibleColumn = startVisibleColumn;
|
||||
@@ -850,7 +875,7 @@ function _renderLine(input: ResolvedRenderLineInput, sb: IStringBuilder): Render
|
||||
const partType = part.type;
|
||||
const partRendersWhitespace = (renderWhitespace !== RenderWhitespace.None && part.isWhitespace());
|
||||
const partRendersWhitespaceWithWidth = partRendersWhitespace && !fontIsMonospace && (partType === 'mtkw'/*only whitespace*/ || !containsForeignElements);
|
||||
const partIsEmptyAndHasPseudoAfter = (charIndex === partEndIndex && part.metadata === LinePartMetadata.PSEUDO_AFTER);
|
||||
const partIsEmptyAndHasPseudoAfter = (charIndex === partEndIndex && part.isPseudoAfter());
|
||||
charOffsetInPart = 0;
|
||||
|
||||
sb.appendASCIIString('<span class="');
|
||||
@@ -882,7 +907,7 @@ function _renderLine(input: ResolvedRenderLineInput, sb: IStringBuilder): Render
|
||||
sb.appendASCII(CharCode.GreaterThan);
|
||||
|
||||
for (; charIndex < partEndIndex; charIndex++) {
|
||||
characterMapping.setPartData(charIndex, partIndex - partDisplacement, charOffsetInPart, partAbsoluteOffset);
|
||||
characterMapping.setColumnInfo(charIndex + 1, partIndex - partDisplacement, charOffsetInPart, partAbsoluteOffset);
|
||||
partDisplacement = 0;
|
||||
const charCode = lineContent.charCodeAt(charIndex);
|
||||
let charWidth: number;
|
||||
@@ -920,7 +945,7 @@ function _renderLine(input: ResolvedRenderLineInput, sb: IStringBuilder): Render
|
||||
sb.appendASCII(CharCode.GreaterThan);
|
||||
|
||||
for (; charIndex < partEndIndex; charIndex++) {
|
||||
characterMapping.setPartData(charIndex, partIndex - partDisplacement, charOffsetInPart, partAbsoluteOffset);
|
||||
characterMapping.setColumnInfo(charIndex + 1, partIndex - partDisplacement, charOffsetInPart, partAbsoluteOffset);
|
||||
partDisplacement = 0;
|
||||
const charCode = lineContent.charCodeAt(charIndex);
|
||||
|
||||
@@ -999,13 +1024,20 @@ function _renderLine(input: ResolvedRenderLineInput, sb: IStringBuilder): Render
|
||||
partDisplacement = 0;
|
||||
}
|
||||
|
||||
if (charIndex >= len && !lastCharacterMappingDefined && part.isPseudoAfter()) {
|
||||
lastCharacterMappingDefined = true;
|
||||
characterMapping.setColumnInfo(charIndex + 1, partIndex, charOffsetInPart, partAbsoluteOffset);
|
||||
}
|
||||
|
||||
sb.appendASCIIString('</span>');
|
||||
|
||||
}
|
||||
|
||||
// When getting client rects for the last character, we will position the
|
||||
// text range at the end of the span, insteaf of at the beginning of next span
|
||||
characterMapping.setPartData(len, parts.length - 1, charOffsetInPart, partAbsoluteOffset);
|
||||
if (!lastCharacterMappingDefined) {
|
||||
// When getting client rects for the last character, we will position the
|
||||
// text range at the end of the span, insteaf of at the beginning of next span
|
||||
characterMapping.setColumnInfo(len + 1, parts.length - 1, charOffsetInPart, partAbsoluteOffset);
|
||||
}
|
||||
|
||||
if (isOverflowing) {
|
||||
sb.appendASCIIString('<span>…</span>');
|
||||
|
||||
@@ -8,7 +8,7 @@ import { WrappingIndent } from 'vs/editor/common/config/editorOptions';
|
||||
import { LineTokens } from 'vs/editor/common/core/lineTokens';
|
||||
import { Position } from 'vs/editor/common/core/position';
|
||||
import { IRange, Range } from 'vs/editor/common/core/range';
|
||||
import { EndOfLinePreference, IActiveIndentGuideInfo, IModelDecoration, IModelDeltaDecoration, ITextModel } from 'vs/editor/common/model';
|
||||
import { EndOfLinePreference, IActiveIndentGuideInfo, IModelDecoration, IModelDeltaDecoration, ITextModel, PositionNormalizationAffinity } from 'vs/editor/common/model';
|
||||
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';
|
||||
@@ -46,6 +46,7 @@ export interface ISplitLine {
|
||||
getModelColumnOfViewPosition(outputLineIndex: number, outputColumn: number): number;
|
||||
getViewPositionOfModelPosition(deltaLineNumber: number, inputColumn: number): Position;
|
||||
getViewLineNumberOfModelPosition(deltaLineNumber: number, inputColumn: number): number;
|
||||
normalizePosition(model: ISimpleModel, modelLineNumber: number, outputLineIndex: number, outputPosition: Position, affinity: PositionNormalizationAffinity): Position;
|
||||
}
|
||||
|
||||
export interface IViewModelLinesCollection extends IDisposable {
|
||||
@@ -75,6 +76,13 @@ export interface IViewModelLinesCollection extends IDisposable {
|
||||
|
||||
getAllOverviewRulerDecorations(ownerId: number, filterOutValidation: boolean, theme: EditorTheme): IOverviewRulerDecorations;
|
||||
getDecorationsInRange(range: Range, ownerId: number, filterOutValidation: boolean): IModelDecoration[];
|
||||
|
||||
normalizePosition(position: Position, affinity: PositionNormalizationAffinity): Position;
|
||||
/**
|
||||
* Gets the column at which indentation stops at a given line.
|
||||
* @internal
|
||||
*/
|
||||
getLineIndentColumn(lineNumber: number): number;
|
||||
}
|
||||
|
||||
export class CoordinatesConverter implements ICoordinatesConverter {
|
||||
@@ -971,6 +979,31 @@ export class SplitLinesCollection implements IViewModelLinesCollection {
|
||||
|
||||
return finalResult;
|
||||
}
|
||||
|
||||
normalizePosition(position: Position, affinity: PositionNormalizationAffinity): Position {
|
||||
const viewLineNumber = this._toValidViewLineNumber(position.lineNumber);
|
||||
const r = this.prefixSumComputer.getIndexOf(viewLineNumber - 1);
|
||||
const lineIndex = r.index;
|
||||
const remainder = r.remainder;
|
||||
|
||||
return this.lines[lineIndex].normalizePosition(this.model, lineIndex + 1, remainder, position, affinity);
|
||||
}
|
||||
|
||||
public getLineIndentColumn(lineNumber: number): number {
|
||||
const viewLineNumber = this._toValidViewLineNumber(lineNumber);
|
||||
const r = this.prefixSumComputer.getIndexOf(viewLineNumber - 1);
|
||||
const lineIndex = r.index;
|
||||
const remainder = r.remainder;
|
||||
|
||||
if (remainder === 0) {
|
||||
return this.model.getLineIndentColumn(lineIndex + 1);
|
||||
}
|
||||
|
||||
// wrapped lines have no indentation.
|
||||
// We deliberately don't handle the case that indentation is wrapped
|
||||
// to avoid two view lines reporting indentation for the very same model line.
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
class VisibleIdentitySplitLine implements ISplitLine {
|
||||
@@ -1046,6 +1079,10 @@ class VisibleIdentitySplitLine implements ISplitLine {
|
||||
public getViewLineNumberOfModelPosition(deltaLineNumber: number, _inputColumn: number): number {
|
||||
return deltaLineNumber;
|
||||
}
|
||||
|
||||
public normalizePosition(model: ISimpleModel, modelLineNumber: number, outputLineIndex: number, outputPosition: Position, affinity: PositionNormalizationAffinity): Position {
|
||||
return outputPosition;
|
||||
}
|
||||
}
|
||||
|
||||
class InvisibleIdentitySplitLine implements ISplitLine {
|
||||
@@ -1108,6 +1145,10 @@ class InvisibleIdentitySplitLine implements ISplitLine {
|
||||
public getViewLineNumberOfModelPosition(_deltaLineNumber: number, _inputColumn: number): number {
|
||||
throw new Error('Not supported');
|
||||
}
|
||||
|
||||
public normalizePosition(model: ISimpleModel, modelLineNumber: number, outputLineIndex: number, outputPosition: Position, affinity: PositionNormalizationAffinity): Position {
|
||||
throw new Error('Not supported');
|
||||
}
|
||||
}
|
||||
|
||||
export class SplitLine implements ISplitLine {
|
||||
@@ -1190,6 +1231,10 @@ export class SplitLine implements ISplitLine {
|
||||
if (!this._isVisible) {
|
||||
throw new Error('Not supported');
|
||||
}
|
||||
return this._getViewLineMinColumn(outputLineIndex);
|
||||
}
|
||||
|
||||
private _getViewLineMinColumn(outputLineIndex: number): number {
|
||||
if (outputLineIndex > 0) {
|
||||
return this._lineBreakData.wrappedTextIndentLength + 1;
|
||||
}
|
||||
@@ -1200,7 +1245,7 @@ export class SplitLine implements ISplitLine {
|
||||
if (!this._isVisible) {
|
||||
throw new Error('Not supported');
|
||||
}
|
||||
return this.getViewLineContent(model, modelLineNumber, outputLineIndex).length + 1;
|
||||
return this.getViewLineLength(model, modelLineNumber, outputLineIndex) + 1;
|
||||
}
|
||||
|
||||
public getViewLineData(model: ISimpleModel, modelLineNumber: number, outputLineIndex: number): ViewLineData {
|
||||
@@ -1298,6 +1343,21 @@ export class SplitLine implements ISplitLine {
|
||||
const r = LineBreakData.getOutputPositionOfInputOffset(this._lineBreakData.breakOffsets, inputColumn - 1);
|
||||
return (deltaLineNumber + r.outputLineIndex);
|
||||
}
|
||||
|
||||
public normalizePosition(model: ISimpleModel, modelLineNumber: number, outputLineIndex: number, outputPosition: Position, affinity: PositionNormalizationAffinity): Position {
|
||||
if (affinity === PositionNormalizationAffinity.Left) {
|
||||
if (outputLineIndex > 0 && outputPosition.column === this._getViewLineMinColumn(outputLineIndex)) {
|
||||
return new Position(outputPosition.lineNumber - 1, this.getViewLineMaxColumn(model, modelLineNumber, outputLineIndex - 1));
|
||||
}
|
||||
}
|
||||
else if (affinity === PositionNormalizationAffinity.Right) {
|
||||
const maxOutputLineIndex = this.getViewLineCount() - 1;
|
||||
if (outputLineIndex < maxOutputLineIndex && outputPosition.column === this.getViewLineMaxColumn(model, modelLineNumber, outputLineIndex)) {
|
||||
return new Position(outputPosition.lineNumber + 1, this._getViewLineMinColumn(outputLineIndex + 1));
|
||||
}
|
||||
}
|
||||
return outputPosition;
|
||||
}
|
||||
}
|
||||
|
||||
let _spaces: string[] = [''];
|
||||
@@ -1532,6 +1592,14 @@ export class IdentityLinesCollection implements IViewModelLinesCollection {
|
||||
public getDecorationsInRange(range: Range, ownerId: number, filterOutValidation: boolean): IModelDecoration[] {
|
||||
return this.model.getDecorationsInRange(range, ownerId, filterOutValidation);
|
||||
}
|
||||
|
||||
normalizePosition(position: Position, affinity: PositionNormalizationAffinity): Position {
|
||||
return this.model.normalizePosition(position, affinity);
|
||||
}
|
||||
|
||||
public getLineIndentColumn(lineNumber: number): number {
|
||||
return this.model.getLineIndentColumn(lineNumber);
|
||||
}
|
||||
}
|
||||
|
||||
class OverviewRulerDecorations {
|
||||
|
||||
@@ -12,7 +12,7 @@ import { IPosition, Position } from 'vs/editor/common/core/position';
|
||||
import { ISelection, Selection } from 'vs/editor/common/core/selection';
|
||||
import { IRange, Range } from 'vs/editor/common/core/range';
|
||||
import { IConfiguration, IViewState, ScrollType, ICursorState, ICommand, INewScrollPosition } from 'vs/editor/common/editorCommon';
|
||||
import { EndOfLinePreference, IActiveIndentGuideInfo, ITextModel, TrackedRangeStickiness, TextModelResolvedOptions, IIdentifiedSingleEditOperation, ICursorStateComputer } from 'vs/editor/common/model';
|
||||
import { EndOfLinePreference, IActiveIndentGuideInfo, ITextModel, TrackedRangeStickiness, TextModelResolvedOptions, IIdentifiedSingleEditOperation, ICursorStateComputer, PositionNormalizationAffinity } from 'vs/editor/common/model';
|
||||
import { ModelDecorationOverviewRulerOptions, ModelDecorationMinimapOptions } from 'vs/editor/common/model/textModel';
|
||||
import * as textModelEvents from 'vs/editor/common/model/textModelEvents';
|
||||
import { ColorId, LanguageId, TokenizationRegistry } from 'vs/editor/common/modes';
|
||||
@@ -1037,4 +1037,16 @@ export class ViewModel extends Disposable implements IViewModel {
|
||||
this._eventDispatcher.endEmitViewEvents();
|
||||
}
|
||||
}
|
||||
|
||||
normalizePosition(position: Position, affinity: PositionNormalizationAffinity): Position {
|
||||
return this._lines.normalizePosition(position, affinity);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the column at which indentation stops at a given line.
|
||||
* @internal
|
||||
*/
|
||||
getLineIndentColumn(lineNumber: number): number {
|
||||
return this._lines.getLineIndentColumn(lineNumber);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user