mirror of
https://github.com/sigmasternchen/xtext-core
synced 2025-03-15 08:18:55 +00:00
RegionDiffFormatter may drop essential changes at the boundary of a
change region #1559 Signed-off-by: Stephan Herrmann <stephan.herrmann@berlin.de>
This commit is contained in:
parent
0afc98c151
commit
45142a25fc
5 changed files with 125 additions and 3 deletions
|
@ -504,4 +504,32 @@ class ChangeSerializerTest {
|
|||
0 3 "#23" -> "#23 subs A A2"
|
||||
'''
|
||||
}
|
||||
|
||||
@Test
|
||||
def void testAddElementsWithEmptyLine() {
|
||||
val uri = "inmemory:/file-add.pstl"
|
||||
val fs = new InMemoryURIHandler()
|
||||
fs += uri -> '''
|
||||
#1 {
|
||||
N1;
|
||||
}
|
||||
'''
|
||||
|
||||
val rs = fs.createResourceSet
|
||||
val model = rs.contents(uri, Node)
|
||||
|
||||
val serializer = newChangeSerializer()
|
||||
serializer.addModification(model.eResource) [
|
||||
model.children += createNode => [name = "N2"]
|
||||
]
|
||||
serializer.endRecordChangesToTextDocuments === '''
|
||||
--------------- inmemory:/file-add.pstl (syntax: <offset|text>) ----------------
|
||||
#1 {
|
||||
N1;
|
||||
<10:0|
|
||||
N2; >}
|
||||
--------------------------------------------------------------------------------
|
||||
10 0 "" -> "\nN2; "
|
||||
'''
|
||||
}
|
||||
}
|
||||
|
|
|
@ -16,6 +16,9 @@ class PartialSerializationTestLanguageFormatter extends AbstractFormatter2 {
|
|||
|
||||
// @Inject extension PartialSerializationTestLanguageGrammarAccess
|
||||
dispatch def format(Node obj, extension IFormattableDocument document) {
|
||||
if (obj.name == "N2") {
|
||||
obj.prepend[newLines=2]
|
||||
}
|
||||
for (r : obj.regionFor.keywords(";")) {
|
||||
r.prepend[noSpace].append[oneSpace]
|
||||
}
|
||||
|
|
|
@ -837,4 +837,51 @@ public class ChangeSerializerTest {
|
|||
_builder_1.newLine();
|
||||
this._changeSerializerTestHelper.operator_tripleEquals(_endRecordChangesToTextDocuments, _builder_1);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAddElementsWithEmptyLine() {
|
||||
final String uri = "inmemory:/file-add.pstl";
|
||||
final InMemoryURIHandler fs = new InMemoryURIHandler();
|
||||
StringConcatenation _builder = new StringConcatenation();
|
||||
_builder.append("#1 {");
|
||||
_builder.newLine();
|
||||
_builder.append("\t");
|
||||
_builder.append("N1;");
|
||||
_builder.newLine();
|
||||
_builder.append("}");
|
||||
_builder.newLine();
|
||||
Pair<String, String> _mappedTo = Pair.<String, String>of(uri, _builder.toString());
|
||||
this._changeSerializerTestHelper.operator_add(fs, _mappedTo);
|
||||
final ResourceSet rs = this._changeSerializerTestHelper.createResourceSet(fs);
|
||||
final Node model = this._changeSerializerTestHelper.<Node>contents(rs, uri, Node.class);
|
||||
final IChangeSerializer serializer = this._changeSerializerTestHelper.newChangeSerializer();
|
||||
final IChangeSerializer.IModification<Resource> _function = (Resource it) -> {
|
||||
EList<Node> _children = model.getChildren();
|
||||
Node _createNode = this.fac.createNode();
|
||||
final Procedure1<Node> _function_1 = (Node it_1) -> {
|
||||
it_1.setName("N2");
|
||||
};
|
||||
Node _doubleArrow = ObjectExtensions.<Node>operator_doubleArrow(_createNode, _function_1);
|
||||
_children.add(_doubleArrow);
|
||||
};
|
||||
serializer.<Resource>addModification(model.eResource(), _function);
|
||||
Collection<IEmfResourceChange> _endRecordChangesToTextDocuments = this._changeSerializerTestHelper.endRecordChangesToTextDocuments(serializer);
|
||||
StringConcatenation _builder_1 = new StringConcatenation();
|
||||
_builder_1.append("--------------- inmemory:/file-add.pstl (syntax: <offset|text>) ----------------");
|
||||
_builder_1.newLine();
|
||||
_builder_1.append("#1 {");
|
||||
_builder_1.newLine();
|
||||
_builder_1.append("\t");
|
||||
_builder_1.append("N1;");
|
||||
_builder_1.newLine();
|
||||
_builder_1.append("<10:0|");
|
||||
_builder_1.newLine();
|
||||
_builder_1.append("N2; >}");
|
||||
_builder_1.newLine();
|
||||
_builder_1.append("--------------------------------------------------------------------------------");
|
||||
_builder_1.newLine();
|
||||
_builder_1.append("10 0 \"\" -> \"\\nN2; \"");
|
||||
_builder_1.newLine();
|
||||
this._changeSerializerTestHelper.operator_tripleEquals(_endRecordChangesToTextDocuments, _builder_1);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -8,6 +8,7 @@
|
|||
*/
|
||||
package org.eclipse.xtext.ide.tests.testlanguage.formatting2;
|
||||
|
||||
import com.google.common.base.Objects;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import org.eclipse.emf.common.util.EList;
|
||||
|
@ -24,15 +25,23 @@ import org.eclipse.xtext.xbase.lib.Procedures.Procedure1;
|
|||
@SuppressWarnings("all")
|
||||
public class PartialSerializationTestLanguageFormatter extends AbstractFormatter2 {
|
||||
protected void _format(final Node obj, @Extension final IFormattableDocument document) {
|
||||
String _name = obj.getName();
|
||||
boolean _equals = Objects.equal(_name, "N2");
|
||||
if (_equals) {
|
||||
final Procedure1<IHiddenRegionFormatter> _function = (IHiddenRegionFormatter it) -> {
|
||||
it.setNewLines(2);
|
||||
};
|
||||
document.<Node>prepend(obj, _function);
|
||||
}
|
||||
List<ISemanticRegion> _keywords = this.textRegionExtensions.regionFor(obj).keywords(";");
|
||||
for (final ISemanticRegion r : _keywords) {
|
||||
final Procedure1<IHiddenRegionFormatter> _function = (IHiddenRegionFormatter it) -> {
|
||||
final Procedure1<IHiddenRegionFormatter> _function_1 = (IHiddenRegionFormatter it) -> {
|
||||
it.noSpace();
|
||||
};
|
||||
final Procedure1<IHiddenRegionFormatter> _function_1 = (IHiddenRegionFormatter it) -> {
|
||||
final Procedure1<IHiddenRegionFormatter> _function_2 = (IHiddenRegionFormatter it) -> {
|
||||
it.oneSpace();
|
||||
};
|
||||
document.append(document.prepend(r, _function), _function_1);
|
||||
document.append(document.prepend(r, _function_1), _function_2);
|
||||
}
|
||||
EList<Node> _children = obj.getChildren();
|
||||
for (final Node child : _children) {
|
||||
|
|
|
@ -16,6 +16,7 @@ import org.eclipse.xtext.formatting2.FormatterRequest;
|
|||
import org.eclipse.xtext.formatting2.IFormattableDocument;
|
||||
import org.eclipse.xtext.formatting2.IFormatter2;
|
||||
import org.eclipse.xtext.formatting2.regionaccess.ITextSegmentDiff;
|
||||
import org.eclipse.xtext.formatting2.regionaccess.internal.TextReplacement;
|
||||
import org.eclipse.xtext.formatting2.regionaccess.ITextRegionAccess;
|
||||
import org.eclipse.xtext.formatting2.regionaccess.ITextRegionAccessDiff;
|
||||
import org.eclipse.xtext.formatting2.regionaccess.ITextRegionRewriter;
|
||||
|
@ -105,6 +106,11 @@ public class RegionDiffFormatter {
|
|||
for (ITextReplacement re : rep) {
|
||||
if (modified.contains(re)) {
|
||||
local.add(re);
|
||||
} else if (hasOverlappingWhitespacePrefix(r, re)) {
|
||||
// change overlaps with a region boundary, trim it to the part within
|
||||
TextReplacement newReplacement = trimReplacement(re, re.getText());
|
||||
if (newReplacement != null)
|
||||
local.add(newReplacement);
|
||||
}
|
||||
}
|
||||
String text;
|
||||
|
@ -119,4 +125,33 @@ public class RegionDiffFormatter {
|
|||
return result;
|
||||
}
|
||||
|
||||
private boolean hasOverlappingWhitespacePrefix(ITextSegmentDiff diff, ITextReplacement re) {
|
||||
String text = re.getText();
|
||||
if (!text.isEmpty()) {
|
||||
ITextSegment modifiedFirstRegion = diff.getModifiedFirstRegion();
|
||||
if (modifiedFirstRegion.contains(re.getOffset())
|
||||
&& modifiedFirstRegion.getText().startsWith(text)) {
|
||||
for (int i=0; i<text.length(); i++) {
|
||||
if (!Character.isWhitespace(text.charAt(i)))
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private TextReplacement trimReplacement(ITextReplacement re, String prefixText) {
|
||||
TextReplacement newReplacement = null;
|
||||
int prefixLen = prefixText.length();
|
||||
String newText = re.getReplacementText();
|
||||
if (newText.length() > prefixLen) {
|
||||
newText = newText.substring(prefixLen);
|
||||
int newOffset = re.getOffset()+prefixLen;
|
||||
int newLength = re.getLength()-prefixLen;
|
||||
newReplacement = new TextReplacement(re.getTextRegionAccess(), newOffset, newLength, newText);
|
||||
}
|
||||
return newReplacement;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue