mirror of
https://github.com/microsoft/vscode.git
synced 2026-04-24 10:38:59 +01:00
Provide an option to insert a final newline (fixes #1666)
This commit is contained in:
@@ -7,6 +7,7 @@
|
||||
|
||||
import { TPromise } from 'vs/base/common/winjs.base';
|
||||
import { sequence } from 'vs/base/common/async';
|
||||
import * as strings from 'vs/base/common/strings';
|
||||
import { ICodeEditorService } from 'vs/editor/common/services/codeEditorService';
|
||||
import { IThreadService } from 'vs/workbench/services/thread/common/threadService';
|
||||
import { ISaveParticipant, ITextFileEditorModel, SaveReason } from 'vs/workbench/services/textfile/common/textfiles';
|
||||
@@ -21,6 +22,7 @@ import { EditOperationsCommand } from 'vs/editor/contrib/format/common/formatCom
|
||||
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
|
||||
import { TextFileEditorModel } from 'vs/workbench/services/textfile/common/textFileEditorModel';
|
||||
import { ExtHostContext, ExtHostDocumentSaveParticipantShape } from './extHost.protocol';
|
||||
import { EditOperation } from 'vs/editor/common/core/editOperation';
|
||||
|
||||
interface INamedSaveParticpant extends ISaveParticipant {
|
||||
readonly name: string;
|
||||
@@ -47,29 +49,18 @@ class TrimWhitespaceParticipant implements INamedSaveParticpant {
|
||||
let prevSelection: Selection[] = [new Selection(1, 1, 1, 1)];
|
||||
const cursors: IPosition[] = [];
|
||||
|
||||
// Find `prevSelection` in any case do ensure a good undo stack when pushing the edit
|
||||
// Collect active cursors in `cursors` only if `isAutoSaved` to avoid having the cursors jump
|
||||
if (model.isAttachedToEditor()) {
|
||||
const allEditors = this.codeEditorService.listCodeEditors();
|
||||
for (let i = 0, len = allEditors.length; i < len; i++) {
|
||||
const editor = allEditors[i];
|
||||
const editorModel = editor.getModel();
|
||||
|
||||
if (!editorModel) {
|
||||
continue; // empty editor
|
||||
}
|
||||
|
||||
if (model === editorModel) {
|
||||
prevSelection = editor.getSelections();
|
||||
if (isAutoSaved) {
|
||||
cursors.push(...prevSelection.map(s => {
|
||||
return {
|
||||
lineNumber: s.positionLineNumber,
|
||||
column: s.positionColumn
|
||||
};
|
||||
}));
|
||||
}
|
||||
}
|
||||
let editor = findEditor(model, this.codeEditorService);
|
||||
if (editor) {
|
||||
// Find `prevSelection` in any case do ensure a good undo stack when pushing the edit
|
||||
// Collect active cursors in `cursors` only if `isAutoSaved` to avoid having the cursors jump
|
||||
prevSelection = editor.getSelections();
|
||||
if (isAutoSaved) {
|
||||
cursors.push(...prevSelection.map(s => {
|
||||
return {
|
||||
lineNumber: s.positionLineNumber,
|
||||
column: s.positionColumn
|
||||
};
|
||||
}));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -82,6 +73,62 @@ class TrimWhitespaceParticipant implements INamedSaveParticpant {
|
||||
}
|
||||
}
|
||||
|
||||
function findEditor(model: IModel, codeEditorService: ICodeEditorService): ICommonCodeEditor {
|
||||
if (model.isAttachedToEditor()) {
|
||||
const allEditors = codeEditorService.listCodeEditors();
|
||||
for (let i = 0, len = allEditors.length; i < len; i++) {
|
||||
const editor = allEditors[i];
|
||||
const editorModel = editor.getModel();
|
||||
|
||||
if (!editorModel) {
|
||||
continue; // empty editor
|
||||
}
|
||||
|
||||
if (model === editorModel) {
|
||||
return editor;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
class FinalNewLineParticipant implements INamedSaveParticpant {
|
||||
|
||||
readonly name = 'FinalNewLineParticipant';
|
||||
|
||||
constructor(
|
||||
@IConfigurationService private configurationService: IConfigurationService,
|
||||
@ICodeEditorService private codeEditorService: ICodeEditorService
|
||||
) {
|
||||
// Nothing
|
||||
}
|
||||
|
||||
public participate(model: ITextFileEditorModel, env: { reason: SaveReason }): any {
|
||||
if (this.configurationService.lookup('files.insertFinalNewline').value) {
|
||||
this.doInsertFinalNewLine(model.textEditorModel);
|
||||
}
|
||||
}
|
||||
|
||||
private doInsertFinalNewLine(model: IModel): void {
|
||||
const lineCount = model.getLineCount();
|
||||
const lastLine = model.getLineContent(lineCount);
|
||||
const lastLineIsEmptyOrWhitespace = strings.lastNonWhitespaceIndex(lastLine) === -1;
|
||||
|
||||
if (lineCount <= 1 || lastLineIsEmptyOrWhitespace) {
|
||||
return;
|
||||
}
|
||||
|
||||
let prevSelection: Selection[] = [new Selection(1, 1, 1, 1)];
|
||||
const editor = findEditor(model, this.codeEditorService);
|
||||
if (editor) {
|
||||
prevSelection = editor.getSelections();
|
||||
}
|
||||
|
||||
model.pushEditOperations(prevSelection, [EditOperation.insert({ lineNumber: lineCount + 1, column: 0 }, model.getEOL())], (edits) => prevSelection);
|
||||
}
|
||||
}
|
||||
|
||||
class FormatOnSaveParticipant implements INamedSaveParticpant {
|
||||
|
||||
readonly name = 'FormatOnSaveParticipant';
|
||||
@@ -204,6 +251,7 @@ export class SaveParticipant implements ISaveParticipant {
|
||||
|
||||
this._saveParticipants = [
|
||||
instantiationService.createInstance(TrimWhitespaceParticipant),
|
||||
instantiationService.createInstance(FinalNewLineParticipant),
|
||||
instantiationService.createInstance(FormatOnSaveParticipant),
|
||||
instantiationService.createInstance(ExtHostSaveParticipant)
|
||||
];
|
||||
|
||||
Reference in New Issue
Block a user