blob: c91a8325032006c44c287dca8ce63e2128251bab [file] [log] [blame]
// Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
import 'dart:async';
import 'package:analysis_server/plugin/protocol/protocol.dart';
import 'package:analysis_server/src/provisional/edit/utilities/change_builder_core.dart';
/**
* A builder used to build a [SourceChange].
*/
class ChangeBuilderImpl implements ChangeBuilder {
/**
* The end-of-line marker used in the file being edited, or `null` if the
* default marker should be used.
*/
String eol = null;
/**
* The change that is being built.
*/
final SourceChange _change = new SourceChange('');
/**
* A table mapping group ids to the associated linked edit groups.
*/
final Map<String, LinkedEditGroup> _linkedEditGroups =
<String, LinkedEditGroup>{};
/**
* Initialize a newly created change builder.
*/
ChangeBuilderImpl();
@override
SourceChange get sourceChange {
_linkedEditGroups.forEach((String name, LinkedEditGroup group) {
_change.addLinkedEditGroup(group);
});
_linkedEditGroups.clear();
return _change;
}
@override
Future<Null> addFileEdit(String path, int fileStamp,
void buildFileEdit(FileEditBuilder builder)) async {
FileEditBuilderImpl builder = await createFileEditBuilder(path, fileStamp);
try {
buildFileEdit(builder);
} finally {
_change.addFileEdit(builder.fileEdit);
}
}
/**
* Create and return a [FileEditBuilder] that can be used to build edits to
* the file with the given [path] and [timeStamp].
*/
Future<FileEditBuilderImpl> createFileEditBuilder(
String path, int timeStamp) async {
return new FileEditBuilderImpl(this, path, timeStamp);
}
/**
* Return the linked edit group with the given [groupName], creating it if it
* did not already exist.
*/
LinkedEditGroup getLinkedEditGroup(String groupName) {
LinkedEditGroup group = _linkedEditGroups[groupName];
if (group == null) {
group = new LinkedEditGroup.empty();
_linkedEditGroups[groupName] = group;
}
return group;
}
}
/**
* A builder used to build a [SourceEdit] as part of a [SourceFileEdit].
*/
class EditBuilderImpl implements EditBuilder {
/**
* The builder being used to create the source file edit of which the source
* edit will be a part.
*/
final FileEditBuilderImpl fileEditBuilder;
/**
* The offset of the region being replaced.
*/
final int offset;
/**
* The length of the region being replaced.
*/
final int length;
/**
* The end-of-line marker used in the file being edited, or `null` if the
* default marker should be used.
*/
String _eol = null;
/**
* The buffer in which the content of the edit is being composed.
*/
final StringBuffer _buffer = new StringBuffer();
/**
* Initialize a newly created builder to build a source edit.
*/
EditBuilderImpl(this.fileEditBuilder, this.offset, this.length) {
_eol = fileEditBuilder.changeBuilder.eol;
}
/**
* Create and return an edit representing the replacement of a region of the
* file with the accumulated text.
*/
SourceEdit get sourceEdit =>
new SourceEdit(offset, length, _buffer.toString());
@override
void addLinkedEdit(
String groupName, void buildLinkedEdit(LinkedEditBuilder builder)) {
LinkedEditBuilderImpl builder = createLinkedEditBuilder();
int start = offset + _buffer.length;
try {
buildLinkedEdit(builder);
} finally {
int end = offset + _buffer.length;
int length = end - start;
Position position = new Position(fileEditBuilder.fileEdit.file, start);
LinkedEditGroup group =
fileEditBuilder.changeBuilder.getLinkedEditGroup(groupName);
group.addPosition(position, length);
for (LinkedEditSuggestion suggestion in builder.suggestions) {
group.addSuggestion(suggestion);
}
}
}
LinkedEditBuilderImpl createLinkedEditBuilder() {
return new LinkedEditBuilderImpl(this);
}
@override
void write(String string) {
_buffer.write(string);
}
@override
void writeln([String string]) {
if (string != null) {
_buffer.write(string);
}
if (_eol == null) {
_buffer.writeln();
} else {
_buffer.write(_eol);
}
}
}
/**
* A builder used to build a [SourceFileEdit] within a [SourceChange].
*/
class FileEditBuilderImpl implements FileEditBuilder {
/**
* The builder being used to create the source change of which the source file
* edit will be a part.
*/
final ChangeBuilderImpl changeBuilder;
/**
* The source file edit that is being built.
*/
final SourceFileEdit fileEdit;
/**
* Initialize a newly created builder to build a source file edit within the
* change being built by the given [changeBuilder]. The file being edited has
* the given absolute [path] and [timeStamp].
*/
FileEditBuilderImpl(this.changeBuilder, String path, int timeStamp)
: fileEdit = new SourceFileEdit(path, timeStamp);
@override
void addInsertion(int offset, void buildEdit(EditBuilder builder)) {
EditBuilderImpl builder = createEditBuilder(offset, 0);
try {
buildEdit(builder);
} finally {
fileEdit.add(builder.sourceEdit);
}
}
@override
void addLinkedPosition(int offset, int length, String groupName) {
LinkedEditGroup group = changeBuilder.getLinkedEditGroup(groupName);
Position position = new Position(fileEdit.file, offset);
group.addPosition(position, length);
}
@override
void addReplacement(
int offset, int length, void buildEdit(EditBuilder builder)) {
EditBuilderImpl builder = createEditBuilder(offset, length);
try {
buildEdit(builder);
} finally {
fileEdit.add(builder.sourceEdit);
}
}
EditBuilderImpl createEditBuilder(int offset, int length) {
return new EditBuilderImpl(this, offset, length);
}
}
/**
* A builder used to build a [LinkedEdit] region within an edit.
*/
class LinkedEditBuilderImpl implements LinkedEditBuilder {
final EditBuilderImpl editBuilder;
final List<LinkedEditSuggestion> suggestions = <LinkedEditSuggestion>[];
LinkedEditBuilderImpl(this.editBuilder);
@override
void addSuggestion(LinkedEditSuggestionKind kind, String value) {
suggestions.add(new LinkedEditSuggestion(value, kind));
}
@override
void addSuggestions(LinkedEditSuggestionKind kind, Iterable<String> values) {
values.forEach((value) => addSuggestion(kind, value));
}
@override
void write(String string) {
editBuilder.write(string);
}
@override
void writeln([String string]) {
editBuilder.writeln(string);
}
}