diff --git a/src/vs/editor/contrib/insertFinalNewLine/browser/insertFinalNewLine.ts b/src/vs/editor/contrib/insertFinalNewLine/browser/insertFinalNewLine.ts new file mode 100644 index 0000000000000..091ccf9788cf5 --- /dev/null +++ b/src/vs/editor/contrib/insertFinalNewLine/browser/insertFinalNewLine.ts @@ -0,0 +1,38 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import { ICodeEditor } from '../../../browser/editorBrowser.js'; +import { EditorAction, registerEditorAction, ServicesAccessor } from '../../../browser/editorExtensions.js'; +import { InsertFinalNewLineCommand } from './insertFinalNewLineCommand.js'; +import { EditorContextKeys } from '../../../common/editorContextKeys.js'; +import * as nls from '../../../../nls.js'; + +export class InsertFinalNewLineAction extends EditorAction { + + public static readonly ID = 'editor.action.insertFinalNewLine'; + + constructor() { + super({ + id: InsertFinalNewLineAction.ID, + label: nls.localize2('insertFinalNewLine', "Insert Final New Line"), + precondition: EditorContextKeys.writable + }); + } + + public run(_accessor: ServicesAccessor, editor: ICodeEditor, args: any): void { + const selection = editor.getSelection(); + if (selection === null) { + return; + } + + const command = new InsertFinalNewLineCommand(selection); + + editor.pushUndoStop(); + editor.executeCommands(this.id, [command]); + editor.pushUndoStop(); + } +} + +registerEditorAction(InsertFinalNewLineAction); diff --git a/src/vs/editor/contrib/insertFinalNewLine/browser/insertFinalNewLineCommand.ts b/src/vs/editor/contrib/insertFinalNewLine/browser/insertFinalNewLineCommand.ts new file mode 100644 index 0000000000000..0b1493d16b710 --- /dev/null +++ b/src/vs/editor/contrib/insertFinalNewLine/browser/insertFinalNewLineCommand.ts @@ -0,0 +1,54 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import * as strings from '../../../../base/common/strings.js'; +import { EditOperation, ISingleEditOperation } from '../../../common/core/editOperation.js'; +import { Position } from '../../../common/core/position.js'; +import { Selection } from '../../../common/core/selection.js'; +import { ICommand, ICursorStateComputerData, IEditOperationBuilder } from '../../../common/editorCommon.js'; +import { ITextModel } from '../../../common/model.js'; + +export class InsertFinalNewLineCommand implements ICommand { + + private readonly _selection: Selection; + private _selectionId: string | null; + + + constructor(selection: Selection) { + this._selection = selection; + this._selectionId = null; + } + + public getEditOperations(model: ITextModel, builder: IEditOperationBuilder): void { + const op = insertFinalNewLine(model); + if (op) { + builder.addEditOperation(op.range, op.text); + } + this._selectionId = builder.trackSelection(this._selection); + } + + public computeCursorState(model: ITextModel, helper: ICursorStateComputerData): Selection { + return helper.getTrackedSelection(this._selectionId!); + } +} + +/** + * Generate edit operations for inserting a final new line if needed. + * Returns undefined if no edit is needed. + */ +export function insertFinalNewLine(model: ITextModel): ISingleEditOperation | undefined { + const lineCount = model.getLineCount(); + const lastLine = model.getLineContent(lineCount); + const lastLineIsEmptyOrWhitespace = strings.lastNonWhitespaceIndex(lastLine) === -1; + + if (!lineCount || lastLineIsEmptyOrWhitespace) { + return; + } + + return EditOperation.insert( + new Position(lineCount, model.getLineMaxColumn(lineCount)), + model.getEOL() + ); +} diff --git a/src/vs/editor/editor.all.ts b/src/vs/editor/editor.all.ts index 3af59c96be09f..9edba1675a3fe 100644 --- a/src/vs/editor/editor.all.ts +++ b/src/vs/editor/editor.all.ts @@ -35,6 +35,7 @@ import './contrib/hover/browser/hoverContribution.js'; import './contrib/indentation/browser/indentation.js'; import './contrib/inlayHints/browser/inlayHintsContribution.js'; import './contrib/inPlaceReplace/browser/inPlaceReplace.js'; +import './contrib/insertFinalNewLine/browser/insertFinalNewLine.js'; import './contrib/lineSelection/browser/lineSelection.js'; import './contrib/linesOperations/browser/linesOperations.js'; import './contrib/linkedEditing/browser/linkedEditing.js';