Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Adding overtype mode #233188

Merged
merged 45 commits into from
Nov 29, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
45 commits
Select commit Hold shift + click to select a range
69e6bff
adding code in order to enable overtype
aiday-mar Nov 6, 2024
5b951f7
adding a setting to determine the cursor style in overtype mode
aiday-mar Nov 6, 2024
b17acbe
adding action to toggle between overtype and insert mode
aiday-mar Nov 6, 2024
1fd450b
adding a contribution which adds a statu bar icon
aiday-mar Nov 6, 2024
c3b3496
adding same as tab focus mode
aiday-mar Nov 11, 2024
f15cac5
polishing
aiday-mar Nov 11, 2024
e8fd730
polish
aiday-mar Nov 12, 2024
0d07ee0
updating by clicking on the status bar
aiday-mar Nov 12, 2024
01de87e
polish
aiday-mar Nov 12, 2024
5048d07
changing the name of the status bar
aiday-mar Nov 12, 2024
4a2b843
add some keybindings and make status bar less prominent
aiday-mar Nov 12, 2024
779035d
polishing the replacement of text
aiday-mar Nov 12, 2024
900af97
adding overtype on paste
aiday-mar Nov 12, 2024
0949847
adding pasting support
aiday-mar Nov 12, 2024
0968f6d
using paste on distributed cursors
aiday-mar Nov 12, 2024
fb0434c
fix ReplaceOvertypeCommandWithOffsetCursorState
aiday-mar Nov 12, 2024
5706284
add code
aiday-mar Nov 13, 2024
44c77db
adding support for composition
aiday-mar Nov 13, 2024
5f03a29
undoing edit context changes
aiday-mar Nov 13, 2024
669ecc1
changing the status bar entry so it disappears when moving to insert …
aiday-mar Nov 13, 2024
d848314
rerender the cursors
aiday-mar Nov 13, 2024
164c67d
allowing composition over several lines
aiday-mar Nov 13, 2024
6a6e9ae
removing log
aiday-mar Nov 13, 2024
24f1dab
polishing the code
aiday-mar Nov 13, 2024
6a5daee
adding tests for overtype mode
aiday-mar Nov 13, 2024
d78453c
reset back the input mode to insert from ovetype on suite teardown
aiday-mar Nov 14, 2024
539e18b
moving inputMode class to the editor folder from the base folder
aiday-mar Nov 19, 2024
47e2c50
remove input mode default value
aiday-mar Nov 19, 2024
09e30fb
removing undefined check on input mode
aiday-mar Nov 19, 2024
473deea
changing the keybindings for `alt+cmd+o`
aiday-mar Nov 19, 2024
619926f
removing the composition payload
aiday-mar Nov 20, 2024
e0276c4
surfacing input mode through cursor configuration
aiday-mar Nov 20, 2024
79744cf
removing disposableness on viewcursor
aiday-mar Nov 20, 2024
7b6a59f
adding effective cursor type
aiday-mar Nov 20, 2024
a539207
removing the usage of the getOffsetAt
aiday-mar Nov 20, 2024
6f706c0
polishing
aiday-mar Nov 21, 2024
2ecbd60
polishing some more
aiday-mar Nov 21, 2024
74aaf07
polishing the code
aiday-mar Nov 21, 2024
83226c4
polishing
aiday-mar Nov 21, 2024
368ae9c
polishing
aiday-mar Nov 21, 2024
acbabe3
Merge branch 'main' into nuclear-swallow
alexdima Nov 26, 2024
3cf0822
removing reading of config service
aiday-mar Nov 27, 2024
43a4c8e
changing the keybiding so it is only on max
aiday-mar Nov 27, 2024
24f6b15
removing reading of config service
aiday-mar Nov 27, 2024
70cc13f
polishing
aiday-mar Nov 27, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions src/vs/editor/browser/config/editorConfiguration.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import { AccessibilitySupport, IAccessibilityService } from '../../../platform/a
import { getWindow, getWindowById } from '../../../base/browser/dom.js';
import { PixelRatio } from '../../../base/browser/pixelRatio.js';
import { MenuId } from '../../../platform/actions/common/actions.js';
import { InputMode } from '../../common/inputMode.js';

export interface IEditorConstructionOptions extends IEditorOptions {
/**
Expand Down Expand Up @@ -95,6 +96,7 @@ export class EditorConfiguration extends Disposable implements IEditorConfigurat
this._register(FontMeasurements.onDidChange(() => this._recomputeOptions()));
this._register(PixelRatio.getInstance(getWindow(container)).onDidChange(() => this._recomputeOptions()));
this._register(this._accessibilityService.onDidChangeScreenReaderOptimized(() => this._recomputeOptions()));
this._register(InputMode.onDidChangeInputMode(() => this._recomputeOptions()));
}

private _recomputeOptions(): void {
Expand Down Expand Up @@ -126,6 +128,7 @@ export class EditorConfiguration extends Disposable implements IEditorConfigurat
emptySelectionClipboard: partialEnv.emptySelectionClipboard,
pixelRatio: partialEnv.pixelRatio,
tabFocusMode: TabFocus.getTabFocusMode(),
inputMode: InputMode.getInputMode(),
accessibilitySupport: partialEnv.accessibilitySupport,
glyphMarginDecorationLaneCount: this._glyphMarginDecorationLaneCount
};
Expand Down
4 changes: 2 additions & 2 deletions src/vs/editor/browser/viewParts/viewCursors/viewCursor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ export class ViewCursor {
const options = this._context.configuration.options;
const fontInfo = options.get(EditorOption.fontInfo);

this._cursorStyle = options.get(EditorOption.cursorStyle);
this._cursorStyle = options.get(EditorOption.effectiveCursorStyle);
this._lineHeight = options.get(EditorOption.lineHeight);
this._typicalHalfwidthCharacterWidth = fontInfo.typicalHalfwidthCharacterWidth;
this._lineCursorWidth = Math.min(options.get(EditorOption.cursorWidth), this._typicalHalfwidthCharacterWidth);
Expand Down Expand Up @@ -130,7 +130,7 @@ export class ViewCursor {
const options = this._context.configuration.options;
const fontInfo = options.get(EditorOption.fontInfo);

this._cursorStyle = options.get(EditorOption.cursorStyle);
this._cursorStyle = options.get(EditorOption.effectiveCursorStyle);
this._lineHeight = options.get(EditorOption.lineHeight);
this._typicalHalfwidthCharacterWidth = fontInfo.typicalHalfwidthCharacterWidth;
this._lineCursorWidth = Math.min(options.get(EditorOption.cursorWidth), this._typicalHalfwidthCharacterWidth);
Expand Down
4 changes: 2 additions & 2 deletions src/vs/editor/browser/viewParts/viewCursors/viewCursors.ts
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ export class ViewCursors extends ViewPart {
const options = this._context.configuration.options;
this._readOnly = options.get(EditorOption.readOnly);
this._cursorBlinking = options.get(EditorOption.cursorBlinking);
this._cursorStyle = options.get(EditorOption.cursorStyle);
this._cursorStyle = options.get(EditorOption.effectiveCursorStyle);
this._cursorSmoothCaretAnimation = options.get(EditorOption.cursorSmoothCaretAnimation);
this._experimentalEditContextEnabled = options.get(EditorOption.experimentalEditContextEnabled);
this._selectionIsEmpty = true;
Expand Down Expand Up @@ -114,7 +114,7 @@ export class ViewCursors extends ViewPart {

this._readOnly = options.get(EditorOption.readOnly);
this._cursorBlinking = options.get(EditorOption.cursorBlinking);
this._cursorStyle = options.get(EditorOption.cursorStyle);
this._cursorStyle = options.get(EditorOption.effectiveCursorStyle);
this._cursorSmoothCaretAnimation = options.get(EditorOption.cursorSmoothCaretAnimation);
this._experimentalEditContextEnabled = options.get(EditorOption.experimentalEditContextEnabled);

Expand Down
86 changes: 86 additions & 0 deletions src/vs/editor/common/commands/replaceCommand.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/

import { Position } from '../core/position.js';
import { Range } from '../core/range.js';
import { Selection, SelectionDirection } from '../core/selection.js';
import { ICommand, ICursorStateComputerData, IEditOperationBuilder } from '../editorCommon.js';
Expand Down Expand Up @@ -31,6 +32,38 @@ export class ReplaceCommand implements ICommand {
}
}

export class ReplaceOvertypeCommand implements ICommand {

private readonly _range: Range;
private readonly _text: string;
public readonly insertsAutoWhitespace: boolean;

constructor(range: Range, text: string, insertsAutoWhitespace: boolean = false) {
this._range = range;
this._text = text;
this.insertsAutoWhitespace = insertsAutoWhitespace;
}

public getEditOperations(model: ITextModel, builder: IEditOperationBuilder): void {
const intialStartPosition = this._range.getStartPosition();
const initialEndPosition = this._range.getEndPosition();
const initialEndLineNumber = initialEndPosition.lineNumber;
const offsetDelta = this._text.length + (this._range.isEmpty() ? 0 : -1);
let endPosition = addPositiveOffsetToModelPosition(model, initialEndPosition, offsetDelta);
if (endPosition.lineNumber > initialEndLineNumber) {
endPosition = new Position(initialEndLineNumber, model.getLineMaxColumn(initialEndLineNumber));
}
const replaceRange = Range.fromPositions(intialStartPosition, endPosition);
builder.addTrackedEditOperation(replaceRange, this._text);
}

public computeCursorState(model: ITextModel, helper: ICursorStateComputerData): Selection {
const inverseEditOperations = helper.getInverseEditOperations();
const srcRange = inverseEditOperations[0].range;
return Selection.fromPositions(srcRange.getEndPosition());
}
}

export class ReplaceCommandThatSelectsText implements ICommand {

private readonly _range: Range;
Expand Down Expand Up @@ -102,6 +135,33 @@ export class ReplaceCommandWithOffsetCursorState implements ICommand {
}
}

export class ReplaceOvertypeCommandOnCompositionEnd implements ICommand {

private readonly _range: Range;

constructor(range: Range) {
this._range = range;
}

public getEditOperations(model: ITextModel, builder: IEditOperationBuilder): void {
const text = model.getValueInRange(this._range);
const initialEndPosition = this._range.getEndPosition();
const initialEndLineNumber = initialEndPosition.lineNumber;
let endPosition = addPositiveOffsetToModelPosition(model, initialEndPosition, text.length);
if (endPosition.lineNumber > initialEndLineNumber) {
endPosition = new Position(initialEndLineNumber, model.getLineMaxColumn(initialEndLineNumber));
}
const replaceRange = Range.fromPositions(initialEndPosition, endPosition);
builder.addTrackedEditOperation(replaceRange, '');
}

public computeCursorState(model: ITextModel, helper: ICursorStateComputerData): Selection {
const inverseEditOperations = helper.getInverseEditOperations();
const srcRange = inverseEditOperations[0].range;
return Selection.fromPositions(srcRange.getEndPosition());
}
}

export class ReplaceCommandThatPreservesSelection implements ICommand {

private readonly _range: Range;
Expand All @@ -127,3 +187,29 @@ export class ReplaceCommandThatPreservesSelection implements ICommand {
return helper.getTrackedSelection(this._selectionId!);
}
}

function addPositiveOffsetToModelPosition(model: ITextModel, position: Position, offset: number): Position {
if (offset < 0) {
throw new Error('Unexpected negative delta');
}
const lineCount = model.getLineCount();
let endPosition = new Position(lineCount, model.getLineMaxColumn(lineCount));
for (let lineNumber = position.lineNumber; lineNumber <= lineCount; lineNumber++) {
if (lineNumber === position.lineNumber) {
const futureOffset = offset - model.getLineMaxColumn(position.lineNumber) + position.column;
if (futureOffset <= 0) {
endPosition = new Position(position.lineNumber, position.column + offset);
break;
}
offset = futureOffset;
} else {
const futureOffset = offset - model.getLineMaxColumn(lineNumber);
if (futureOffset <= 0) {
endPosition = new Position(lineNumber, offset);
break;
}
offset = futureOffset;
}
}
return endPosition;
}
46 changes: 44 additions & 2 deletions src/vs/editor/common/config/editorOptions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -239,10 +239,19 @@ export interface IEditorOptions {
*/
cursorSmoothCaretAnimation?: 'off' | 'explicit' | 'on';
/**
* Control the cursor style, either 'block' or 'line'.
* Control the cursor style in insert mode.
* Defaults to 'line'.
*/
cursorStyle?: 'line' | 'block' | 'underline' | 'line-thin' | 'block-outline' | 'underline-thin';
/**
* Control the cursor style in overtype mode.
* Defaults to 'block'.
*/
overtypeCursorStyle?: 'line' | 'block' | 'underline' | 'line-thin' | 'block-outline' | 'underline-thin';
/**
* Controls whether paste in overtype mode should overwrite or insert.
*/
overtypeOnPaste?: boolean;
/**
* Control the width of the cursor when cursorStyle is set to 'line'
*/
Expand Down Expand Up @@ -974,6 +983,7 @@ export interface IEnvironmentalOptions {
readonly emptySelectionClipboard: boolean;
readonly pixelRatio: number;
readonly tabFocusMode: boolean;
readonly inputMode: 'insert' | 'overtype';
readonly accessibilitySupport: AccessibilitySupport;
readonly glyphMarginDecorationLaneCount: number;
}
Expand Down Expand Up @@ -1889,6 +1899,23 @@ class EditorFontInfo extends ComputedEditorOption<EditorOption.fontInfo, FontInf

//#endregion

//#region effectiveCursorStyle

class EffectiveCursorStyle extends ComputedEditorOption<EditorOption.effectiveCursorStyle, TextEditorCursorStyle> {

constructor() {
super(EditorOption.effectiveCursorStyle);
}

public compute(env: IEnvironmentalOptions, options: IComputedEditorOptions, _: TextEditorCursorStyle): TextEditorCursorStyle {
return env.inputMode === 'overtype' ?
options.get(EditorOption.overtypeCursorStyle) :
options.get(EditorOption.cursorStyle);
}
}

//#endregion

//#region fontSize

class EditorFontSize extends SimpleEditorOption<EditorOption.fontSize, number> {
Expand Down Expand Up @@ -5424,6 +5451,8 @@ export const enum EditorOption {
multiCursorLimit,
occurrencesHighlight,
occurrencesHighlightDelay,
overtypeCursorStyle,
overtypeOnPaste,
overviewRulerBorder,
overviewRulerLanes,
padding,
Expand Down Expand Up @@ -5486,6 +5515,7 @@ export const enum EditorOption {
showDeprecated,
inlayHints,
// Leave these at the end (because they have dependencies!)
effectiveCursorStyle,
editorClassName,
pixelRatio,
tabFocusMode,
Expand Down Expand Up @@ -5710,7 +5740,14 @@ export const EditorOptions = {
TextEditorCursorStyle.Line, 'line',
['line', 'block', 'underline', 'line-thin', 'block-outline', 'underline-thin'],
cursorStyleFromString,
{ description: nls.localize('cursorStyle', "Controls the cursor style.") }
{ description: nls.localize('cursorStyle', "Controls the cursor style in insert input mode.") }
)),
overtypeCursorStyle: register(new EditorEnumOption(
EditorOption.overtypeCursorStyle, 'overtypeCursorStyle',
TextEditorCursorStyle.Block, 'block',
['line', 'block', 'underline', 'line-thin', 'block-outline', 'underline-thin'],
cursorStyleFromString,
{ description: nls.localize('overtypeCursorStyle', "Controls the cursor style in overtype input mode.") }
)),
aiday-mar marked this conversation as resolved.
Show resolved Hide resolved
cursorSurroundingLines: register(new EditorIntOption(
EditorOption.cursorSurroundingLines, 'cursorSurroundingLines',
Expand Down Expand Up @@ -5967,6 +6004,10 @@ export const EditorOptions = {
tags: ['preview']
}
)),
overtypeOnPaste: register(new EditorBooleanOption(
EditorOption.overtypeOnPaste, 'overtypeOnPaste', true,
{ description: nls.localize('overtypeOnPaste', "Controls whether pasting should overtype.") }
)),
overviewRulerBorder: register(new EditorBooleanOption(
EditorOption.overviewRulerBorder, 'overviewRulerBorder', true,
{ description: nls.localize('overviewRulerBorder', "Controls whether a border should be drawn around the overview ruler.") }
Expand Down Expand Up @@ -6291,6 +6332,7 @@ export const EditorOptions = {
)),

// Leave these at the end (because they have dependencies!)
effectiveCursorStyle: register(new EffectiveCursorStyle()),
editorClassName: register(new EditorClassName()),
defaultColorDecorators: register(new EditorBooleanOption(
EditorOption.defaultColorDecorators, 'defaultColorDecorators', true,
Expand Down
31 changes: 19 additions & 12 deletions src/vs/editor/common/cursor/cursor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1020,8 +1020,9 @@ export class CommandExecutor {
class CompositionLineState {
constructor(
public readonly text: string,
public readonly startSelection: number,
public readonly endSelection: number
public readonly lineNumber: number,
public readonly startSelectionOffset: number,
public readonly endSelectionOffset: number
) { }
}

Expand All @@ -1035,8 +1036,10 @@ class CompositionState {
if (selection.startLineNumber !== selection.endLineNumber) {
return null;
}
const lineNumber = selection.startLineNumber;
result.push(new CompositionLineState(
textModel.getLineContent(selection.startLineNumber),
textModel.getLineContent(lineNumber),
lineNumber,
selection.startColumn - 1,
selection.endColumn - 1
));
Expand Down Expand Up @@ -1072,24 +1075,28 @@ class CompositionState {

private static _deduceOutcome(original: CompositionLineState, current: CompositionLineState): CompositionOutcome {
const commonPrefix = Math.min(
original.startSelection,
current.startSelection,
original.startSelectionOffset,
current.startSelectionOffset,
strings.commonPrefixLength(original.text, current.text)
);
const commonSuffix = Math.min(
original.text.length - original.endSelection,
current.text.length - current.endSelection,
original.text.length - original.endSelectionOffset,
current.text.length - current.endSelectionOffset,
strings.commonSuffixLength(original.text, current.text)
);
const deletedText = original.text.substring(commonPrefix, original.text.length - commonSuffix);
const insertedText = current.text.substring(commonPrefix, current.text.length - commonSuffix);
const insertedTextStartOffset = commonPrefix;
const insertedTextEndOffset = current.text.length - commonSuffix;
const insertedText = current.text.substring(insertedTextStartOffset, insertedTextEndOffset);
const insertedTextRange = new Range(current.lineNumber, insertedTextStartOffset + 1, current.lineNumber, insertedTextEndOffset + 1);
return new CompositionOutcome(
deletedText,
original.startSelection - commonPrefix,
original.endSelection - commonPrefix,
original.startSelectionOffset - commonPrefix,
original.endSelectionOffset - commonPrefix,
insertedText,
current.startSelection - commonPrefix,
current.endSelection - commonPrefix
current.startSelectionOffset - commonPrefix,
current.endSelectionOffset - commonPrefix,
insertedTextRange
);
}
}
Loading
Loading