Open kolovos opened 1 month ago
Below is some code we could use to map offsets of formatted code back to the original code assuming the formatter has only added/removed whitespace (which is the case for the outdentation formatter)
package org.eclipse.epsilon.egl.formatter;
import java.util.ArrayList;
import java.util.List;
public class PositionMapper {
public static List<Integer> mapOffsets(String original, String formatted) {
// Helper variables to track the current index in both strings
int originalIndex = 0, formattedIndex = 0;
// Create an array to store the mapped offsets of each character in the original string
int[] mappedOffsets = new int[original.length()];
// Process both strings simultaneously
while (originalIndex < original.length() && formattedIndex < formatted.length()) {
char originalChar = original.charAt(originalIndex);
char formattedChar = formatted.charAt(formattedIndex);
// If characters match, map the current formatted index to the original index
if (formattedIndex < formatted.length() && originalChar == formattedChar) {
mappedOffsets[originalIndex] = formattedIndex;
originalIndex++;
formattedIndex++;
} else if (Character.isWhitespace(originalChar)) {
// Handle cases where the characters differ by continuing through the original string
mappedOffsets[originalIndex] = -1;
originalIndex++;
} else if (Character.isWhitespace(formattedChar)) {
formattedIndex++;
}
}
// If there are remaining characters in the original string that weren't mapped yet
while (originalIndex < original.length()) {
mappedOffsets[originalIndex] = formattedIndex; // Remaining original chars map to end of formatted
originalIndex++;
}
ArrayList<Integer> mappedOffsetsList = new ArrayList<Integer>();
for (int mappedOffset : mappedOffsets) mappedOffsetsList.add(mappedOffset);
return mappedOffsetsList;
}
public static void main(String[] args) {
// Example usage
String original = "Hello\t\n\nWorld!";
String formatted = "Hello\n\t\t World!";
List<Integer> originalOffsets = new ArrayList<>();
originalOffsets.add(0); // H
originalOffsets.add(6); // W
List<Integer> formattedOffsets = mapOffsets(original, formatted);
int originalOffset = 0;
for (Integer mappedOffset : formattedOffsets) {
char mappedChar = mappedOffset >= 0 ? formatted.charAt(mappedOffset) : ' ';
System.out.println(originalOffset + "->" + mappedOffset + " / " + original.charAt(originalOffset) + "->" + mappedChar);
originalOffset++;
}
}
}
EGL's recently-introduced outdentation feature, breaks traceability links. For example, if the template from the EGX playground example is modified as follows (outdentation added in line 6)
the reported trace links for task titles are broken (see below)
This is because outdentation is implemented partly using a post-transformation formatter, and formatters are expected to deal with updating traceability themselves (which the outdentation formatter doesn't).
Given that most formatters only add/remove whitespace, we could introduce an abstract e.g.
TraceabilityPreservingFormatter
class that updates trace links given only the original and the formatted text and make EGL'sOutdentationFormatter
, as well as other formatters, extend it. To deal with cases where formatters actually do more than adding/removing whitespace,TraceabilityPreservingFormatter
could actually check that the original/formatted text only differ in whitespace and fail or report a warning otherwise.