Skip to content

Commit 9bb90bd

Browse files
authored
trim whitespace when deleting new line character (microsoft#210870)
* trim whitespace after new line character deletion * trimming whitespace after deleting newline character + tests -- feature request microsoft#134898 * Implement deleting right at end of line includes leading whitespace --------- Co-authored-by: Alexandru Dima <[email protected]>
2 parents d8af289 + a11e611 commit 9bb90bd

File tree

5 files changed

+117
-76
lines changed

5 files changed

+117
-76
lines changed

src/vs/editor/common/config/editorOptions.ts

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -735,6 +735,11 @@ export interface IEditorOptions {
735735
* Inserting and deleting whitespace follows tab stops.
736736
*/
737737
useTabStops?: boolean;
738+
/**
739+
* Controls whether the editor should automatically remove indentation whitespace when joining lines with Delete.
740+
* Defaults to false.
741+
*/
742+
trimWhitespaceOnDelete?: boolean;
738743
/**
739744
* The font family
740745
*/
@@ -5721,6 +5726,7 @@ export const enum EditorOption {
57215726
suggestSelection,
57225727
tabCompletion,
57235728
tabIndex,
5729+
trimWhitespaceOnDelete,
57245730
unicodeHighlighting,
57255731
unusualLineTerminators,
57265732
useShadowDOM,
@@ -6512,6 +6518,10 @@ export const EditorOptions = {
65126518
EditorOption.tabIndex, 'tabIndex',
65136519
0, -1, Constants.MAX_SAFE_SMALL_INTEGER
65146520
)),
6521+
trimWhitespaceOnDelete: register(new EditorBooleanOption(
6522+
EditorOption.trimWhitespaceOnDelete, 'trimWhitespaceOnDelete', false,
6523+
{ description: nls.localize('trimWhitespaceOnDelete', "Controls whether the editor will also delete the next line's indentation whitespace when deleting a newline.") }
6524+
)),
65156525
unicodeHighlight: register(new UnicodeHighlight()),
65166526
unusualLineTerminators: register(new EditorStringEnumOption(
65176527
EditorOption.unusualLineTerminators, 'unusualLineTerminators',

src/vs/editor/common/cursor/cursorDeleteOperations.ts

Lines changed: 34 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -23,18 +23,7 @@ export class DeleteOperations {
2323
for (let i = 0, len = selections.length; i < len; i++) {
2424
const selection = selections[i];
2525

26-
let deleteSelection: Range = selection;
27-
28-
if (deleteSelection.isEmpty()) {
29-
const position = selection.getPosition();
30-
const rightOfPosition = MoveOperations.right(config, model, position);
31-
deleteSelection = new Range(
32-
rightOfPosition.lineNumber,
33-
rightOfPosition.column,
34-
position.lineNumber,
35-
position.column
36-
);
37-
}
26+
const deleteSelection = this.getDeleteRightRange(selection, model, config);
3827

3928
if (deleteSelection.isEmpty()) {
4029
// Probably at end of file => ignore
@@ -51,6 +40,37 @@ export class DeleteOperations {
5140
return [shouldPushStackElementBefore, commands];
5241
}
5342

43+
private static getDeleteRightRange(selection: Selection, model: ICursorSimpleModel, config: CursorConfiguration): Range {
44+
if (!selection.isEmpty()) {
45+
return selection;
46+
}
47+
48+
const position = selection.getPosition();
49+
const rightOfPosition = MoveOperations.right(config, model, position);
50+
51+
if (config.trimWhitespaceOnDelete && rightOfPosition.lineNumber !== position.lineNumber) {
52+
// Smart line join (deleting leading whitespace) is on
53+
// (and) Delete is happening at the end of a line
54+
const firstNonWhitespaceColumn = model.getLineFirstNonWhitespaceColumn(rightOfPosition.lineNumber);
55+
if (firstNonWhitespaceColumn > 0) {
56+
// The next line has content
57+
return new Range(
58+
rightOfPosition.lineNumber,
59+
firstNonWhitespaceColumn,
60+
position.lineNumber,
61+
position.column
62+
);
63+
}
64+
}
65+
66+
return new Range(
67+
rightOfPosition.lineNumber,
68+
rightOfPosition.column,
69+
position.lineNumber,
70+
position.column
71+
);
72+
}
73+
5474
public static isAutoClosingPairDelete(
5575
autoClosingDelete: EditorAutoClosingEditStrategy,
5676
autoClosingBrackets: EditorAutoClosingStrategy,
@@ -150,7 +170,7 @@ export class DeleteOperations {
150170
const commands: Array<ICommand | null> = [];
151171
let shouldPushStackElementBefore = (prevEditOperationType !== EditOperationType.DeletingLeft);
152172
for (let i = 0, len = selections.length; i < len; i++) {
153-
const deleteRange = DeleteOperations.getDeleteRange(selections[i], model, config);
173+
const deleteRange = DeleteOperations.getDeleteLeftRange(selections[i], model, config);
154174

155175
// Ignore empty delete ranges, as they have no effect
156176
// They happen if the cursor is at the beginning of the file.
@@ -169,7 +189,7 @@ export class DeleteOperations {
169189

170190
}
171191

172-
private static getDeleteRange(selection: Selection, model: ICursorSimpleModel, config: CursorConfiguration,): Range {
192+
private static getDeleteLeftRange(selection: Selection, model: ICursorSimpleModel, config: CursorConfiguration): Range {
173193
if (!selection.isEmpty()) {
174194
return selection;
175195
}

src/vs/editor/common/cursorCommon.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,7 @@ export class CursorConfiguration {
6060
public readonly lineHeight: number;
6161
public readonly typicalHalfwidthCharacterWidth: number;
6262
public readonly useTabStops: boolean;
63+
public readonly trimWhitespaceOnDelete: boolean;
6364
public readonly wordSeparators: string;
6465
public readonly emptySelectionClipboard: boolean;
6566
public readonly copyWithSyntaxHighlighting: boolean;
@@ -98,6 +99,7 @@ export class CursorConfiguration {
9899
|| e.hasChanged(EditorOption.autoClosingOvertype)
99100
|| e.hasChanged(EditorOption.autoSurround)
100101
|| e.hasChanged(EditorOption.useTabStops)
102+
|| e.hasChanged(EditorOption.trimWhitespaceOnDelete)
101103
|| e.hasChanged(EditorOption.fontInfo)
102104
|| e.hasChanged(EditorOption.readOnly)
103105
|| e.hasChanged(EditorOption.wordSegmenterLocales)
@@ -126,6 +128,7 @@ export class CursorConfiguration {
126128
this.typicalHalfwidthCharacterWidth = fontInfo.typicalHalfwidthCharacterWidth;
127129
this.pageSize = Math.max(1, Math.floor(layoutInfo.height / this.lineHeight) - 2);
128130
this.useTabStops = options.get(EditorOption.useTabStops);
131+
this.trimWhitespaceOnDelete = options.get(EditorOption.trimWhitespaceOnDelete);
129132
this.wordSeparators = options.get(EditorOption.wordSeparators);
130133
this.emptySelectionClipboard = options.get(EditorOption.emptySelectionClipboard);
131134
this.copyWithSyntaxHighlighting = options.get(EditorOption.copyWithSyntaxHighlighting);

src/vs/editor/common/standalone/standaloneEnums.ts

Lines changed: 32 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -313,37 +313,38 @@ export enum EditorOption {
313313
suggestSelection = 136,
314314
tabCompletion = 137,
315315
tabIndex = 138,
316-
unicodeHighlighting = 139,
317-
unusualLineTerminators = 140,
318-
useShadowDOM = 141,
319-
useTabStops = 142,
320-
wordBreak = 143,
321-
wordSegmenterLocales = 144,
322-
wordSeparators = 145,
323-
wordWrap = 146,
324-
wordWrapBreakAfterCharacters = 147,
325-
wordWrapBreakBeforeCharacters = 148,
326-
wordWrapColumn = 149,
327-
wordWrapOverride1 = 150,
328-
wordWrapOverride2 = 151,
329-
wrappingIndent = 152,
330-
wrappingStrategy = 153,
331-
showDeprecated = 154,
332-
inertialScroll = 155,
333-
inlayHints = 156,
334-
wrapOnEscapedLineFeeds = 157,
335-
effectiveCursorStyle = 158,
336-
editorClassName = 159,
337-
pixelRatio = 160,
338-
tabFocusMode = 161,
339-
layoutInfo = 162,
340-
wrappingInfo = 163,
341-
defaultColorDecorators = 164,
342-
colorDecoratorsActivatedOn = 165,
343-
inlineCompletionsAccessibilityVerbose = 166,
344-
effectiveEditContext = 167,
345-
scrollOnMiddleClick = 168,
346-
effectiveAllowVariableFonts = 169
316+
trimWhitespaceOnDelete = 139,
317+
unicodeHighlighting = 140,
318+
unusualLineTerminators = 141,
319+
useShadowDOM = 142,
320+
useTabStops = 143,
321+
wordBreak = 144,
322+
wordSegmenterLocales = 145,
323+
wordSeparators = 146,
324+
wordWrap = 147,
325+
wordWrapBreakAfterCharacters = 148,
326+
wordWrapBreakBeforeCharacters = 149,
327+
wordWrapColumn = 150,
328+
wordWrapOverride1 = 151,
329+
wordWrapOverride2 = 152,
330+
wrappingIndent = 153,
331+
wrappingStrategy = 154,
332+
showDeprecated = 155,
333+
inertialScroll = 156,
334+
inlayHints = 157,
335+
wrapOnEscapedLineFeeds = 158,
336+
effectiveCursorStyle = 159,
337+
editorClassName = 160,
338+
pixelRatio = 161,
339+
tabFocusMode = 162,
340+
layoutInfo = 163,
341+
wrappingInfo = 164,
342+
defaultColorDecorators = 165,
343+
colorDecoratorsActivatedOn = 166,
344+
inlineCompletionsAccessibilityVerbose = 167,
345+
effectiveEditContext = 168,
346+
scrollOnMiddleClick = 169,
347+
effectiveAllowVariableFonts = 170
347348
}
348349

349350
/**

src/vs/monaco.d.ts

Lines changed: 38 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -3886,6 +3886,11 @@ declare namespace monaco.editor {
38863886
* Inserting and deleting whitespace follows tab stops.
38873887
*/
38883888
useTabStops?: boolean;
3889+
/**
3890+
* Controls whether the editor should automatically remove indentation whitespace when joining lines with Delete.
3891+
* Defaults to false.
3892+
*/
3893+
trimWhitespaceOnDelete?: boolean;
38893894
/**
38903895
* The font family
38913896
*/
@@ -5188,37 +5193,38 @@ declare namespace monaco.editor {
51885193
suggestSelection = 136,
51895194
tabCompletion = 137,
51905195
tabIndex = 138,
5191-
unicodeHighlighting = 139,
5192-
unusualLineTerminators = 140,
5193-
useShadowDOM = 141,
5194-
useTabStops = 142,
5195-
wordBreak = 143,
5196-
wordSegmenterLocales = 144,
5197-
wordSeparators = 145,
5198-
wordWrap = 146,
5199-
wordWrapBreakAfterCharacters = 147,
5200-
wordWrapBreakBeforeCharacters = 148,
5201-
wordWrapColumn = 149,
5202-
wordWrapOverride1 = 150,
5203-
wordWrapOverride2 = 151,
5204-
wrappingIndent = 152,
5205-
wrappingStrategy = 153,
5206-
showDeprecated = 154,
5207-
inertialScroll = 155,
5208-
inlayHints = 156,
5209-
wrapOnEscapedLineFeeds = 157,
5210-
effectiveCursorStyle = 158,
5211-
editorClassName = 159,
5212-
pixelRatio = 160,
5213-
tabFocusMode = 161,
5214-
layoutInfo = 162,
5215-
wrappingInfo = 163,
5216-
defaultColorDecorators = 164,
5217-
colorDecoratorsActivatedOn = 165,
5218-
inlineCompletionsAccessibilityVerbose = 166,
5219-
effectiveEditContext = 167,
5220-
scrollOnMiddleClick = 168,
5221-
effectiveAllowVariableFonts = 169
5196+
trimWhitespaceOnDelete = 139,
5197+
unicodeHighlighting = 140,
5198+
unusualLineTerminators = 141,
5199+
useShadowDOM = 142,
5200+
useTabStops = 143,
5201+
wordBreak = 144,
5202+
wordSegmenterLocales = 145,
5203+
wordSeparators = 146,
5204+
wordWrap = 147,
5205+
wordWrapBreakAfterCharacters = 148,
5206+
wordWrapBreakBeforeCharacters = 149,
5207+
wordWrapColumn = 150,
5208+
wordWrapOverride1 = 151,
5209+
wordWrapOverride2 = 152,
5210+
wrappingIndent = 153,
5211+
wrappingStrategy = 154,
5212+
showDeprecated = 155,
5213+
inertialScroll = 156,
5214+
inlayHints = 157,
5215+
wrapOnEscapedLineFeeds = 158,
5216+
effectiveCursorStyle = 159,
5217+
editorClassName = 160,
5218+
pixelRatio = 161,
5219+
tabFocusMode = 162,
5220+
layoutInfo = 163,
5221+
wrappingInfo = 164,
5222+
defaultColorDecorators = 165,
5223+
colorDecoratorsActivatedOn = 166,
5224+
inlineCompletionsAccessibilityVerbose = 167,
5225+
effectiveEditContext = 168,
5226+
scrollOnMiddleClick = 169,
5227+
effectiveAllowVariableFonts = 170
52225228
}
52235229

52245230
export const EditorOptions: {
@@ -5367,6 +5373,7 @@ declare namespace monaco.editor {
53675373
suggestSelection: IEditorOption<EditorOption.suggestSelection, 'first' | 'recentlyUsed' | 'recentlyUsedByPrefix'>;
53685374
tabCompletion: IEditorOption<EditorOption.tabCompletion, 'on' | 'off' | 'onlySnippets'>;
53695375
tabIndex: IEditorOption<EditorOption.tabIndex, number>;
5376+
trimWhitespaceOnDelete: IEditorOption<EditorOption.trimWhitespaceOnDelete, boolean>;
53705377
unicodeHighlight: IEditorOption<EditorOption.unicodeHighlighting, any>;
53715378
unusualLineTerminators: IEditorOption<EditorOption.unusualLineTerminators, 'off' | 'auto' | 'prompt'>;
53725379
useShadowDOM: IEditorOption<EditorOption.useShadowDOM, boolean>;

0 commit comments

Comments
 (0)