提交 1429c4ec 编写于 作者: A Alexandru Dima 提交者: GitHub

Merge pull request #33947 from AiryShift/master

Create setting that trims newlines from the end of a file
......@@ -127,6 +127,53 @@ export class FinalNewLineParticipant implements INamedSaveParticpant {
}
}
export class TrimFinalNewLinesParticipant implements INamedSaveParticpant {
readonly name = 'TrimFinalNewLinesParticipant';
constructor(
@IConfigurationService private configurationService: IConfigurationService,
@ICodeEditorService private codeEditorService: ICodeEditorService
) {
// Nothing
}
public participate(model: ITextFileEditorModel, env: { reason: SaveReason }): void {
if (this.configurationService.lookup('files.trimFinalNewlines', { overrideIdentifier: model.textEditorModel.getLanguageIdentifier().language, resource: model.getResource() }).value) {
this.doTrimFinalNewLines(model.textEditorModel);
}
}
private doTrimFinalNewLines(model: IModel): void {
const lineCount = model.getLineCount();
// Do not insert new line if file does not end with new line
if (!lineCount) {
return;
}
let prevSelection: Selection[] = [new Selection(1, 1, 1, 1)];
const editor = findEditor(model, this.codeEditorService);
if (editor) {
prevSelection = editor.getSelections();
}
let currentLineNumber = model.getLineCount();
let currentLine = model.getLineContent(currentLineNumber);
let currentLineIsEmptyOrWhitespace = strings.lastNonWhitespaceIndex(currentLine) === -1;
while (currentLineIsEmptyOrWhitespace) {
currentLineNumber--;
currentLine = model.getLineContent(currentLineNumber);
currentLineIsEmptyOrWhitespace = strings.lastNonWhitespaceIndex(currentLine) === -1;
}
model.pushEditOperations(prevSelection, [EditOperation.delete(new Range(currentLineNumber + 1, 1, lineCount + 1, 1))], edits => prevSelection);
if (editor) {
editor.setSelections(prevSelection);
}
}
}
class FormatOnSaveParticipant implements INamedSaveParticpant {
readonly name = 'FormatOnSaveParticipant';
......@@ -237,6 +284,7 @@ export class SaveParticipant implements ISaveParticipant {
new TrimWhitespaceParticipant(configurationService, codeEditorService),
new FormatOnSaveParticipant(codeEditorService, configurationService),
new FinalNewLineParticipant(configurationService, codeEditorService),
new TrimFinalNewLinesParticipant(configurationService, codeEditorService),
new ExtHostSaveParticipant(extHostContext)
];
......
......@@ -235,6 +235,13 @@ configurationRegistry.registerConfiguration({
'overridable': true,
'scope': ConfigurationScope.RESOURCE
},
'files.trimFinalNewlines': {
'type': 'boolean',
'default': false,
'description': nls.localize('trimFinalNewlines', "When enabled, will trim all new lines after the final new line at the end of the file when saving it."),
'overridable': true,
'scope': ConfigurationScope.RESOURCE
},
'files.autoSave': {
'type': 'string',
'enum': [AutoSaveConfiguration.OFF, AutoSaveConfiguration.AFTER_DELAY, AutoSaveConfiguration.ON_FOCUS_CHANGE, , AutoSaveConfiguration.ON_WINDOW_CHANGE],
......
......@@ -7,7 +7,7 @@
import * as assert from 'assert';
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
import { FinalNewLineParticipant } from 'vs/workbench/api/electron-browser/mainThreadSaveParticipant';
import { FinalNewLineParticipant, TrimFinalNewLinesParticipant } from 'vs/workbench/api/electron-browser/mainThreadSaveParticipant';
import { TestConfigurationService } from 'vs/platform/configuration/test/common/testConfigurationService';
import { workbenchInstantiationService, TestTextFileService } from 'vs/workbench/test/workbenchTestServices';
import { toResource } from 'vs/base/test/common/utils';
......@@ -72,4 +72,44 @@ suite('MainThreadSaveParticipant', function () {
done();
});
});
test('trim final new lines', function (done) {
const model: TextFileEditorModel = instantiationService.createInstance(TextFileEditorModel, toResource.call(this, '/path/trim_final_new_line.txt'), 'utf8');
model.load().then(() => {
const configService = new TestConfigurationService();
configService.setUserConfiguration('files', { 'trimFinalNewlines': true });
const participant = new TrimFinalNewLinesParticipant(configService, undefined);
const textContent = 'Trim New Line';
const eol = `${model.textEditorModel.getEOL()}`;
// No new line removal if last line is not new line
let lineContent = `${textContent}`;
model.textEditorModel.setValue(lineContent);
participant.participate(model, { reason: SaveReason.EXPLICIT });
assert.equal(model.getValue(), lineContent);
// No new line removal if last line is single new line
lineContent = `${textContent}${eol}`;
model.textEditorModel.setValue(lineContent);
participant.participate(model, { reason: SaveReason.EXPLICIT });
assert.equal(model.getValue(), lineContent);
// Remove new line (single line with two new lines)
lineContent = `${textContent}${eol}${eol}`;
model.textEditorModel.setValue(lineContent);
participant.participate(model, { reason: SaveReason.EXPLICIT });
assert.equal(model.getValue(), `${textContent}${eol}`);
// Remove new lines (multiple lines with multiple new lines)
lineContent = `${textContent}${eol}${textContent}${eol}${eol}${eol}`;
model.textEditorModel.setValue(lineContent);
participant.participate(model, { reason: SaveReason.EXPLICIT });
assert.equal(model.getValue(), `${textContent}${eol}${textContent}${eol}`);
done();
});
});
});
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册