protected void assertAllWhitespaceIsFormatted(ITextRegionAccess access, List<ITextReplacement> replacements) { List<ITextSegment> expected = Lists.newArrayList(); IHiddenRegion current = access.regionForRootEObject().getPreviousHiddenRegion(); while (current != null) { expected.addAll(current.getMergedSpaces()); current = current.getNextHiddenRegion(); } List<ITextSegment> missing = TextRegions.difference(expected, replacements); if (!missing.isEmpty()) { TextRegionsToString toString = new TextRegionsToString().setTextRegionAccess(access); for (ITextSegment region : missing) toString.add(region, region.getClass().getSimpleName()); String msg = "The following regions are not formatted:\n" + toString; System.err.println(msg); Assert.fail(msg); } }
@Override public String toString() { ITextRegionAccess access = getTextRegionAccess(); ITextSegment frame = getFrame(); if (access == null || frame == null) return "(null)"; ITextRegionRewriter rewriter = access.getRewriter(); StringBuilder builder = new StringBuilder(); List<ITextReplacement> replacements = Lists.newArrayList(); for (int i = 0; i < this.items.size(); i++) { Item item = this.items.get(i); ITextSegment region = item.getRegion(); String regionStr = "offset=" + region.getOffset() + " length=" + region.getLength(); String open = i < BRACKETS_OPEN.length ? BRACKETS_OPEN[i] : "[" + i + "["; String close = i < BRACKETS_CLOSE.length ? BRACKETS_CLOSE[i] : "]" + i + "]"; builder.append(open + close + ": " + item.getTitle() + " at " + regionStr + "\n"); replacements.add(rewriter.createReplacement(region.getOffset(), 0, open)); replacements.add(rewriter.createReplacement(region.getEndOffset(), 0, close)); } String vizualized = rewriter.renderToString(frame, replacements); builder.append(box("document snippet", vizualized)); return builder.toString(); }
@Override public void renderToAppendable(ITextSegment input, Iterable<? extends ITextReplacement> rep, Appendable result) throws IOException { int offset = input.getOffset(); String text = input.getText(); List<ITextReplacement> list = new TextReplacementList<ITextReplacement>(rep); Collections.sort(list); int lastOffset = 0; for (ITextReplacement r : list) { result.append(text.subSequence(lastOffset, r.getOffset() - offset)); result.append(r.getReplacementText()); lastOffset = (r.getOffset() - offset) + r.getLength(); } if (lastOffset <= text.length()) result.append(text.subSequence(lastOffset, text.length())); }
protected String applyTextReplacements(Iterable<ITextReplacement> replacements) { ITextSegment region = getRegion(); String input = region.getText(); ArrayList<ITextReplacement> list = Lists.newArrayList(replacements); Collections.sort(list); int startOffset = region.getOffset(); int lastOffset = 0; StringBuilder result = new StringBuilder(); for (ITextReplacement r : list) { int offset = r.getOffset() - startOffset; result.append(input.subSequence(lastOffset, offset)); result.append(r.getReplacementText()); lastOffset = offset + r.getLength(); } result.append(input.subSequence(lastOffset, input.length())); return result.toString(); }
@Override public List<ITextReplacement> getReplacementsUntil(ITextReplacerContext first) { ITextReplacerContext current = this; List<Iterable<ITextReplacement>> reversedReplacements = Lists.newArrayList(); while (current != null) { Iterable<ITextReplacement> localReplacements = current.getLocalReplacements(); if (!Iterables.isEmpty(localReplacements)) reversedReplacements.add(localReplacements); if (current == first) break; current = current.getPreviousContext(); } Collections.reverse(reversedReplacements); List<ITextReplacement> flattenedReplacements = new TextReplacementList<ITextReplacement>(); for (Iterable<ITextReplacement> chunk : reversedReplacements) Iterables.addAll(flattenedReplacements, chunk); return flattenedReplacements; }
protected String toStringLocal() { List<String> items = Lists.newArrayList(); if (autowrap) items.add("autowrap"); if (canAutowrap != null && canAutowrap >= 0) items.add("canAutowrap"); if (replacer != null) { ITextSegment region = replacer.getRegion(); items.add(format("replacer=[%d-%d-%s|%s]", region.getOffset(), region.getLength(), replacer.getClass().getSimpleName(), replacer.toString())); } if (replacements != null) for (ITextReplacement r : replacements) { String fmt = "replacement=[%d-%d|%s]"; items.add(format(fmt, r.getOffset(), r.getLength(), r.getReplacementText())); } return Joiner.on("; ").join(items); }
@Override public boolean isWrapInRegion() { ITextRegionAccess access = getDocument().getRequest().getTextRegionAccess(); ITextSegment region = getReplacer().getRegion(); int lastOffset = region.getOffset(); for (ITextReplacement rep : this.getLocalReplacements()) { int endOffset = rep.getOffset(); String between = access.textForOffset(lastOffset, endOffset - lastOffset); if (between.contains("\n") || rep.getReplacementText().contains("\n")) { return true; } lastOffset = rep.getEndOffset(); } String rest = access.textForOffset(lastOffset, region.getEndOffset() - lastOffset); if (rest.contains("\n")) { return true; } return false; }
@Override public final List<ITextReplacement> format(FormatterRequest request) { try { initialize(request); XtextResource xtextResource = request.getTextRegionAccess().getResource(); IFormattableDocument document = createFormattableRootDocument(); try { format(xtextResource, document); } catch (RegionTraceMissingException e) { document = handleTraceMissing(document, e); } List<ITextReplacement> rendered = document.renderToTextReplacements(); List<ITextReplacement> postprocessed = postProcess(document, rendered); return postprocessed; } finally { reset(); } }
protected List<ITextReplacement> mergeReplacements(ITextRegionAccessDiff regions, List<ITextReplacement> rep) { ITextRegionRewriter rewriter = regions.getOriginalTextRegionAccess().getRewriter(); List<ITextReplacement> result = Lists.newArrayList(); for (ITextSegmentDiff r : regions.getRegionDifferences()) { int originalStart = r.getOriginalFirstRegion().getOffset(); int originalLength = r.getOriginalLastRegion().getEndOffset() - originalStart; int modifiedStart = r.getModifiedFirstRegion().getOffset(); int modifiedLength = r.getModifiedLastRegion().getEndOffset() - modifiedStart; ITextSegment modifiedRegion = regions.regionForOffset(modifiedStart, modifiedLength); List<ITextReplacement> local = Lists.newArrayList(); for (ITextReplacement re : rep) { if (modifiedRegion.contains(re)) { local.add(re); } } String newText; if (local.isEmpty()) { newText = modifiedRegion.getText(); } else { newText = regions.getRewriter().renderToString(modifiedRegion, local); } ITextReplacement replacement = rewriter.createReplacement(originalStart, originalLength, newText); result.add(replacement); } return result; }
protected List<ITextReplacement> format2(final XtextResource resource, final ITextRegion selection, final ITypedPreferenceValues preferences) { final FormatterRequest request = this.formatterRequestProvider.get(); request.setAllowIdentityEdits(false); request.setFormatUndefinedHiddenRegionsOnly(false); if ((selection != null)) { request.setRegions(Collections.<ITextRegion>unmodifiableList(CollectionLiterals.<ITextRegion>newArrayList(selection))); } if ((preferences != null)) { request.setPreferences(preferences); } final ITextRegionAccess regionAccess = this.regionBuilder.forNodeModel(resource).create(); request.setTextRegionAccess(regionAccess); final IFormatter2 formatter2 = this.formatter2Provider.get(); final List<ITextReplacement> replacements = formatter2.format(request); return replacements; }
@Override protected TextEdit createTextEdit(List<ITextReplacement> replacements) { if (replacements.isEmpty()) { return new ReplaceEdit(0, 0, ""); } ITextRegionAccess regionAccess = replacements.get(0).getTextRegionAccess(); String newDocument = regionAccess.getRewriter().renderToString(replacements); return new ReplaceEdit(0, regionAccess.regionForDocument().getLength(), newDocument); }
public void assertFormatted(FormatterTestRequest req) { checkNotNull(req); checkNotNull(req.getToBeFormatted()); FormatterRequest request = req.getRequest(); checkArgument(request.getTextRegionAccess() == null); String document = req.getToBeFormatted().toString(); XtextResource parsed = parse(document); if (req.isAllowSyntaxErrors()) { request.setExceptionHandler(ExceptionAcceptor.IGNORING); } else { assertNoSyntaxErrors(parsed); request.setExceptionHandler(ExceptionAcceptor.THROWING); } request.setTextRegionAccess(createRegionAccess(parsed, req)); if (request.getPreferences() == null) request.setPreferences(new MapBasedPreferenceValues(Maps.<String, String> newLinkedHashMap())); List<ITextReplacement> replacements = createFormatter(req).format(request); assertReplacementsAreInRegion(replacements, request.getRegions(), document); if (!req.isAllowUnformattedWhitespace()) assertAllWhitespaceIsFormatted(request.getTextRegionAccess(), replacements); String formatted = request.getTextRegionAccess().getRewriter().renderToString(replacements); Assert.assertEquals(req.getExpectationOrToBeFormatted().toString(), formatted); // TODO: assert formatting a second time only produces identity replacements // TODO: assert formatting with undefined whitespace only }
protected void assertReplacementsAreInRegion(List<ITextReplacement> rep, Collection<ITextRegion> regions, String doc) { Set<ITextReplacement> invalid = Sets.newHashSet(); ALLOWED: for (ITextRegion allowed : regions) for (ITextReplacement r : rep) { if (allowed.contains(r)) continue ALLOWED; invalid.add(r); } if (!invalid.isEmpty()) { String visualized = new TextRegionsToString().addAllReplacements(invalid).toString(); fail("One or more TextReplacements are outside of the allowed region. Region: " + regions, visualized); } }
protected void serialize(EObject obj, Appendable appendable, SaveOptions options) throws IOException { ITextRegionAccess regionAccess = serializeToRegions(obj); FormatterRequest request = formatterRequestProvider.get(); request.setFormatUndefinedHiddenRegionsOnly(!options.isFormatting()); request.setTextRegionAccess(regionAccess); IFormatter2 formatter2 = formatter2Provider.get(); List<ITextReplacement> replacements = formatter2.format(request); regionAccess.getRewriter().renderToAppendable(replacements, appendable); }
public ITextRegionAccess getTextRegionAccess() { if (this.textRegionAccess != null) return this.textRegionAccess; for (ITextReplacement item : this.items) return item.getTextRegionAccess(); return null; }
@Override public String renderToString(Iterable<? extends ITextReplacement> replacements) { StringBuilder result = new StringBuilder(); try { renderToAppendable(replacements, result); } catch (IOException e) { throw new RuntimeException(e); } return result.toString(); }
@Override public String renderToString(ITextSegment input, Iterable<? extends ITextReplacement> replacements) { StringBuilder result = new StringBuilder(); try { renderToAppendable(input, replacements, result); } catch (IOException e) { throw new RuntimeException(e); } return result.toString(); }
@Override public ITextReplacerContext createReplacements(ITextReplacerContext context) { ITextReplacerContext last = super.createReplacements(context); List<ITextReplacement> replacements = last.getReplacementsUntil(context); String string = applyTextReplacements(replacements); if (string.contains("\n")) throw new FormattingNotApplicableException(); int leadingCharCount = context.getLeadingCharsInLineCount(); int formattedLength = string.length(); int lineLength = leadingCharCount + formattedLength; if (lineLength > maxLineWidth) throw new FormattingNotApplicableException(); return last; }
@Override public List<ITextReplacement> renderToTextReplacements() { ITextReplacerContext first = getFormatter().createTextReplacerContext(this); ITextReplacerContext last = createReplacements(first); List<ITextReplacement> replacements = last.getReplacementsUntil(first); return replacements; }
protected TextSegmentSet<ITextReplacement> createTextReplacementsSet() { return new ArrayListTextSegmentSet<ITextReplacement>(Functions.<ITextReplacement>identity(), new Function<ITextReplacement, String>() { @Override public String apply(ITextReplacement input) { return input.getReplacementText(); } }, getDocument().getRequest().isEnableDebugTracing()); }
@Override public Iterable<ITextReplacement> getLocalReplacements() { if (replacements != null) return replacements; else return Collections.<ITextReplacement>emptyList(); }
@Override public Iterable<ITextReplacement> getLocalReplacementsReverse() { if (replacements != null) return replacements.reverseIterable(); else return Collections.<ITextReplacement>emptyList(); }
protected boolean isInRequestedRange(ITextReplacement repl) { Collection<ITextRegion> regions = document.getRequest().getRegions(); if (regions.isEmpty()) return true; for (org.eclipse.xtext.util.ITextRegion region : regions) if (region.getOffset() <= repl.getOffset() && region.getOffset() + region.getLength() >= repl.getEndOffset()) return true; return false; }
@Override public void addReplacement(ITextReplacement replacement) { Preconditions.checkNotNull(replacer); ITextSegment replacerRegion = replacer.getRegion(); FormatterRequest request = document.getRequest(); if (!replacerRegion.contains(replacement)) { String frameTitle = replacer.getClass().getSimpleName(); ITextSegment frameRegion = replacer.getRegion(); String replacerTitle = replacement.getReplacementText(); RegionsOutsideFrameException exception = new RegionsOutsideFrameException(frameTitle, frameRegion, Tuples.create(replacerTitle, (ITextSegment) replacement)); request.getExceptionHandler().accept(exception); return; } if (!isInRequestedRange(replacement)) { return; } if (!isInUndefinedRegion(replacement)) { if (request.isFormatUndefinedHiddenRegionsOnly()) { return; } if (!request.allowIdentityEdits() && isIdentityEdit(replacement)) { return; } } try { replacements.add(replacement); } catch (ConflictingRegionsException e) { request.getExceptionHandler().accept(e); } }
private WorkspaceEdit recordWorkspaceEdit(final Document doc, final XtextResource resource, final IChangeSerializer.IModification<Resource> mod) { try { final XtextResourceSet rs = new XtextResourceSet(); final Resource copy = rs.createResource(resource.getURI()); String _text = resource.getParseResult().getRootNode().getText(); StringInputStream _stringInputStream = new StringInputStream(_text); copy.load(_stringInputStream, CollectionLiterals.<Object, Object>emptyMap()); this.serializer.<Resource>addModification(copy, mod); final ArrayList<IEmfResourceChange> documentchanges = CollectionLiterals.<IEmfResourceChange>newArrayList(); this.serializer.applyModifications(CollectionBasedAcceptor.<IEmfResourceChange>of(documentchanges)); WorkspaceEdit _workspaceEdit = new WorkspaceEdit(); final Procedure1<WorkspaceEdit> _function = (WorkspaceEdit it) -> { Iterable<ITextDocumentChange> _filter = Iterables.<ITextDocumentChange>filter(documentchanges, ITextDocumentChange.class); for (final ITextDocumentChange documentchange : _filter) { { final Function1<ITextReplacement, TextEdit> _function_1 = (ITextReplacement replacement) -> { TextEdit _textEdit = new TextEdit(); final Procedure1<TextEdit> _function_2 = (TextEdit it_1) -> { it_1.setNewText(replacement.getReplacementText()); Position _position = doc.getPosition(replacement.getOffset()); Position _position_1 = doc.getPosition(replacement.getEndOffset()); Range _range = new Range(_position, _position_1); it_1.setRange(_range); }; return ObjectExtensions.<TextEdit>operator_doubleArrow(_textEdit, _function_2); }; final List<TextEdit> edits = ListExtensions.<ITextReplacement, TextEdit>map(documentchange.getReplacements(), _function_1); it.getChanges().put(documentchange.getNewURI().toString(), edits); } } }; return ObjectExtensions.<WorkspaceEdit>operator_doubleArrow(_workspaceEdit, _function); } catch (Throwable _e) { throw Exceptions.sneakyThrow(_e); } }
public void assertFormatted(FormatterTestRequest req) { checkNotNull(req); checkNotNull(req.getToBeFormatted()); FormatterRequest request = req.getRequest(); checkArgument(request.getTextRegionAccess() == null); String document = req.getToBeFormatted().toString(); XtextResource parsed = parse(document); if (req.isAllowSyntaxErrors()) { if (request.getExplicitExceptionHandler() == null) { request.setExceptionHandler(ExceptionAcceptor.IGNORING); } } else { assertNoSyntaxErrors(parsed); if (request.getExplicitExceptionHandler() == null) { request.setExceptionHandler(ExceptionAcceptor.THROWING); } } request.setTextRegionAccess(createRegionAccess(parsed, req)); if (request.getPreferences() == null) request.setPreferences(new MapBasedPreferenceValues(Maps.<String, String> newLinkedHashMap())); List<ITextReplacement> replacements = createFormatter(req).format(request); assertReplacementsAreInRegion(replacements, request.getRegions(), document); if (!req.isAllowUnformattedWhitespace()) assertAllWhitespaceIsFormatted(request.getTextRegionAccess(), replacements); String formatted = request.getTextRegionAccess().getRewriter().renderToString(replacements); Assert.assertEquals(req.getExpectationOrToBeFormatted().toString(), formatted); // TODO: assert formatting a second time only produces identity replacements // TODO: assert formatting with undefined whitespace only }
@Override public void applyChange(Deltas deltas, IAcceptor<IEmfResourceChange> changeAcceptor) { XtextResource res = (XtextResource) lifecycleManager.openAndApplyReferences(getResourceSet(), getResource()); if (!referenceUpdater.isAffected(deltas, getResource())) { return; } ITextRegionAccess base = textRegionBuilderProvider.get().forNodeModel(res).create(); ITextRegionDiffBuilder rewriter = new StringBasedTextRegionAccessDiffBuilder(base); ReferenceUpdaterContext context = new ReferenceUpdaterContext(deltas, rewriter); referenceUpdater.update(context); if (!context.getModifications().isEmpty()) { ChangeRecorder rec = new ChangeRecorder(res); for (Runnable run : context.getModifications()) { run.run(); } ChangeDescription recording = rec.endRecording(); ResourceSet rs = res.getResourceSet(); ResourceSetRecording tree = changeTreeProvider.createChangeTree(rs, Collections.emptyList(), recording); ResourceRecording recordedResource = tree.getRecordedResource(res); serializer.serializeChanges(recordedResource, rewriter); } for (IUpdatableReference upd : context.getUpdatableReferences()) { referenceUpdater.updateReference(rewriter, upd); } ITextRegionAccessDiff rewritten = rewriter.create(); List<ITextReplacement> rep = formatter.format(rewritten); TextDocumentChange change = new TextDocumentChange(rewritten, getResource().getUri(), rep); changeAcceptor.accept(change); }
@Override public void applyChange(Deltas deltas, IAcceptor<IEmfResourceChange> changeAcceptor) { Resource resource = snapshot.getResource(); ResourceSet rs = resource.getResourceSet(); ReferenceUpdaterContext ctx = new ReferenceUpdaterContext(deltas, document); if (serializer.isUpdateCrossReferences()) { referenceUpdater.update(ctx); for (Runnable run : ctx.getModifications()) { run.run(); } } ChangeDescription recording = recorder.endRecording(); if (recording != null) { List<IResourceSnapshot> snapshots = Collections.singletonList(snapshot); ResourceSetRecording tree = changeTreeProvider.createChangeTree(rs, snapshots, recording); ResourceRecording recordedResource = tree.getRecordedResource(resource); partialSerializer.serializeChanges(recordedResource, document); } List<IUpdatableReference> updatableReferences = ctx.getUpdatableReferences(); for (IUpdatableReference upd : updatableReferences) { referenceUpdater.updateReference(document, upd); } ITextRegionAccessDiff rewritten = document.create(); List<ITextReplacement> rep = formatter.format(rewritten); URI oldUri = snapshot.getURI(); TextDocumentChange change = new TextDocumentChange(rewritten, oldUri, rep); changeAcceptor.accept(change); }
public List<TextEdit> format(final XtextResource resource, final Document document, final int offset, final int length) { if ((this.formatter2Provider != null)) { TextRegion _textRegion = new TextRegion(offset, length); final List<ITextReplacement> replacements = this.format2(resource, _textRegion, null); final Function1<ITextReplacement, TextEdit> _function = (ITextReplacement r) -> { return this.toTextEdit(document, r.getReplacementText(), r.getOffset(), r.getLength()); }; return IterableExtensions.<TextEdit>toList(ListExtensions.<ITextReplacement, TextEdit>map(replacements, _function)); } else { return CollectionLiterals.<TextEdit>newArrayList(); } }
public TextRegionsToString add(ITextReplacement region) { return add(region, region.getReplacementText()); }
public TextRegionsToString addAllReplacements(Iterable<? extends ITextReplacement> regions) { for (ITextReplacement region : regions) addReplacement((ITextSegment) region, region.getReplacementText()); return this; }
public TextRegionsToString addReplacement(ITextReplacement region, String description) { return addReplacement(region, region.getReplacementText(), description); }
public TextRegionsInTextToString add(ITextReplacement region) { items.add(region); return this; }
public List<ITextReplacement> getItems() { return items; }
@Override public void renderToAppendable(Iterable<? extends ITextReplacement> replacements, Appendable result) throws IOException { renderToAppendable(access.regionForDocument(), replacements, result); }
@Override public ITextReplacement createReplacement(int offset, int length, String text) { return new TextReplacement(access, offset, length, text); }
@Override public ITextReplacement replaceWith(String text) { return getTextRegionAccess().getRewriter().createReplacement(getOffset(), getLength(), text); }
protected boolean isIdentityEdit(ITextReplacement replacement) { return replacement.getText().equals(replacement.getReplacementText()); }