mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
maintain smartpointer to each host psi element to survive documentWindow when psi modification leads to he whole host replacement
This commit is contained in:
@@ -36,6 +36,7 @@ import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.util.Disposer;
|
||||
import com.intellij.openapi.util.ProperTextRange;
|
||||
import com.intellij.openapi.util.TextRange;
|
||||
import com.intellij.openapi.util.text.StringUtil;
|
||||
import com.intellij.psi.*;
|
||||
import com.intellij.psi.impl.source.tree.PsiCommentImpl;
|
||||
import com.intellij.psi.util.PsiTreeUtil;
|
||||
@@ -191,7 +192,8 @@ public class MyTestInjector {
|
||||
Disposer.register(parent, new Disposable() {
|
||||
@Override
|
||||
public void dispose() {
|
||||
InjectedLanguageManager.getInstance(psiManager.getProject()).unregisterMultiHostInjector(myMultiHostInjector);
|
||||
boolean b = InjectedLanguageManager.getInstance(psiManager.getProject()).unregisterMultiHostInjector(myMultiHostInjector);
|
||||
assert b;
|
||||
}
|
||||
});
|
||||
|
||||
@@ -250,8 +252,32 @@ public class MyTestInjector {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (host instanceof PsiComment && ((PsiComment)host).getTokenType() == JavaTokenType.C_STYLE_COMMENT) {
|
||||
/* {{{
|
||||
* js code
|
||||
* js code
|
||||
* }}}
|
||||
*/
|
||||
String text = host.getText();
|
||||
String prefix = "/*\n * {{{\n";
|
||||
String suffix = " }}}\n */";
|
||||
if (text.startsWith(prefix) && text.endsWith(suffix)) {
|
||||
String s = StringUtil.trimEnd(StringUtil.trimStart(text, prefix), suffix);
|
||||
int off = 0;
|
||||
while (!s.isEmpty()) {
|
||||
String t = s.trim();
|
||||
if (t.startsWith("*")) t = t.substring(1).trim();
|
||||
int i = s.length() - t.length();
|
||||
placesToInject.addPlace(js, TextRange.from(prefix.length() + off, i), "", "\n");
|
||||
off += i;
|
||||
s = s.substring(i);
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (host instanceof PsiCommentImpl) {
|
||||
String text = host.getText();
|
||||
if (text.startsWith("/*--{") && text.endsWith("}--*/")) {
|
||||
@@ -275,6 +301,7 @@ public class MyTestInjector {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// inject to all string literal initializers of variables named 'ql'
|
||||
if (host instanceof PsiLiteralExpression && ((PsiLiteralExpression)host).getValue() instanceof String) {
|
||||
PsiVariable variable = PsiTreeUtil.getParentOfType(host, PsiVariable.class);
|
||||
|
||||
@@ -20,7 +20,7 @@
|
||||
package com.intellij.injected.editor;
|
||||
|
||||
import com.intellij.openapi.editor.Document;
|
||||
import com.intellij.openapi.editor.RangeMarker;
|
||||
import com.intellij.openapi.util.Segment;
|
||||
import com.intellij.openapi.util.TextRange;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
@@ -45,7 +45,7 @@ public interface DocumentWindow extends Document {
|
||||
int injectedToHostLine(int line);
|
||||
|
||||
@NotNull
|
||||
RangeMarker[] getHostRanges();
|
||||
Segment[] getHostRanges();
|
||||
|
||||
boolean areRangesEqual(@NotNull DocumentWindow documentWindow);
|
||||
|
||||
|
||||
@@ -16,10 +16,10 @@
|
||||
|
||||
package com.intellij.psi;
|
||||
|
||||
import com.intellij.openapi.editor.RangeMarker;
|
||||
import com.intellij.openapi.util.ProperTextRange;
|
||||
import com.intellij.openapi.util.Segment;
|
||||
import com.intellij.openapi.util.TextRange;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@@ -49,63 +49,27 @@ public interface PsiLanguageInjectionHost extends PsiElement {
|
||||
void visit(@NotNull PsiFile injectedPsi, @NotNull List<Shred> places);
|
||||
}
|
||||
|
||||
class Shred {
|
||||
public PsiLanguageInjectionHost host;
|
||||
private final RangeMarker relevantRangeInHost;
|
||||
public final TextRange range; // range in (decoded) PSI
|
||||
public final String prefix;
|
||||
public final String suffix;
|
||||
interface Shred {
|
||||
@Nullable("returns null when the host document marker is invalid")
|
||||
Segment getHostRangeMarker();
|
||||
|
||||
public Shred(@NotNull PsiLanguageInjectionHost host, @NotNull final RangeMarker relevantRangeInHost, @NotNull String prefix, @NotNull String suffix, @NotNull TextRange range) {
|
||||
this.host = host;
|
||||
this.relevantRangeInHost = relevantRangeInHost;
|
||||
this.prefix = prefix;
|
||||
this.suffix = suffix;
|
||||
this.range = range;
|
||||
assert isValid();
|
||||
assert relevantRangeInHost.isValid();
|
||||
}
|
||||
@NotNull
|
||||
TextRange getRangeInsideHost();
|
||||
|
||||
public RangeMarker getHostRangeMarker() {
|
||||
return relevantRangeInHost;
|
||||
}
|
||||
boolean isValid();
|
||||
|
||||
public TextRange getRangeInsideHost() {
|
||||
TextRange hostTextRange = host.getTextRange();
|
||||
ProperTextRange textRange = relevantRangeInHost.isValid() ? new ProperTextRange(relevantRangeInHost.getStartOffset(), relevantRangeInHost.getEndOffset()) : null;
|
||||
textRange = textRange == null ? null : textRange.intersection(hostTextRange);
|
||||
if (textRange == null) return new ProperTextRange(0, hostTextRange.getLength());
|
||||
return textRange.shiftRight(-hostTextRange.getStartOffset());
|
||||
}
|
||||
void dispose();
|
||||
|
||||
@SuppressWarnings({"HardCodedStringLiteral"})
|
||||
public String toString() {
|
||||
return "Shred "+ host.getTextRange() + ": "+ host+
|
||||
" Inhost range: "+(relevantRangeInHost.isValid() ? "" : "!") + "(" + relevantRangeInHost.getStartOffset()+","+relevantRangeInHost.getEndOffset()+");" +
|
||||
" PSI range: "+range;
|
||||
}
|
||||
@Nullable
|
||||
PsiLanguageInjectionHost getHost();
|
||||
|
||||
public boolean isValid() {
|
||||
return relevantRangeInHost.isValid() && host.isValid();
|
||||
}
|
||||
@NotNull
|
||||
TextRange getRange();
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) return true;
|
||||
if (o == null || getClass() != o.getClass()) return false;
|
||||
@NotNull
|
||||
String getPrefix();
|
||||
|
||||
Shred shred = (Shred)o;
|
||||
|
||||
return host.equals(shred.host) &&
|
||||
prefix.equals(shred.prefix) &&
|
||||
suffix.equals(shred.suffix) &&
|
||||
range.equals(shred.range) &&
|
||||
TextRange.create(relevantRangeInHost).equals(TextRange.create(shred.relevantRangeInHost));
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return range.hashCode();
|
||||
}
|
||||
@NotNull
|
||||
String getSuffix();
|
||||
}
|
||||
}
|
||||
|
||||
+2
-2
@@ -342,7 +342,7 @@ public class GeneralHighlightingPass extends ProgressableTextEditorHighlightingP
|
||||
if (documentWindow == null) return true;
|
||||
Place places = InjectedLanguageUtil.getShreds(injectedPsi);
|
||||
for (PsiLanguageInjectionHost.Shred place : places) {
|
||||
TextRange textRange = place.getRangeInsideHost().shiftRight(place.host.getTextRange().getStartOffset());
|
||||
TextRange textRange = place.getRangeInsideHost().shiftRight(place.getHost().getTextRange().getStartOffset());
|
||||
if (textRange.isEmpty()) continue;
|
||||
String desc = injectedPsi.getLanguage().getDisplayName() + ": " + injectedPsi.getText();
|
||||
HighlightInfo info = HighlightInfo.createHighlightInfo(HighlightInfoType.INJECTED_LANGUAGE_BACKGROUND, textRange, null, desc, injectedAttributes);
|
||||
@@ -457,7 +457,7 @@ public class GeneralHighlightingPass extends ProgressableTextEditorHighlightingP
|
||||
// finds the first nearest text range
|
||||
private static TextRange findNearestTextRange(final DocumentWindow documentWindow, final int startOffset) {
|
||||
TextRange textRange = null;
|
||||
for (RangeMarker marker : documentWindow.getHostRanges()) {
|
||||
for (Segment marker : documentWindow.getHostRanges()) {
|
||||
TextRange curRange = ProperTextRange.create(marker);
|
||||
if (curRange.getStartOffset() > startOffset && textRange != null) break;
|
||||
textRange = curRange;
|
||||
|
||||
@@ -27,10 +27,7 @@ import com.intellij.openapi.editor.ex.DocumentEx;
|
||||
import com.intellij.openapi.editor.ex.EditReadOnlyListener;
|
||||
import com.intellij.openapi.editor.ex.LineIterator;
|
||||
import com.intellij.openapi.editor.ex.RangeMarkerEx;
|
||||
import com.intellij.openapi.util.Pair;
|
||||
import com.intellij.openapi.util.ProperTextRange;
|
||||
import com.intellij.openapi.util.TextRange;
|
||||
import com.intellij.openapi.util.UserDataHolderBase;
|
||||
import com.intellij.openapi.util.*;
|
||||
import com.intellij.openapi.util.text.StringUtil;
|
||||
import com.intellij.psi.PsiLanguageInjectionHost;
|
||||
import com.intellij.psi.impl.source.tree.injected.Place;
|
||||
@@ -64,8 +61,8 @@ public class DocumentWindowImpl extends UserDataHolderBase implements Disposable
|
||||
synchronized (myLock) {
|
||||
myShreds = shreds;
|
||||
}
|
||||
myPrefixLineCount = Math.max(1, 1 + StringUtil.countNewLines(shreds.get(0).prefix));
|
||||
mySuffixLineCount = Math.max(1, 1 + StringUtil.countNewLines(shreds.get(shreds.size()- 1).suffix));
|
||||
myPrefixLineCount = Math.max(1, 1 + StringUtil.countNewLines(shreds.get(0).getPrefix()));
|
||||
mySuffixLineCount = Math.max(1, 1 + StringUtil.countNewLines(shreds.get(shreds.size()- 1).getSuffix()));
|
||||
}
|
||||
|
||||
@Nullable("null means we were unable to calculate")
|
||||
@@ -79,8 +76,10 @@ public class DocumentWindowImpl extends UserDataHolderBase implements Disposable
|
||||
for (int i = myShreds.size() - 1; i >= 0; i--) {
|
||||
PsiLanguageInjectionHost.Shred shred = myShreds.get(i);
|
||||
if (!shred.isValid()) continue;
|
||||
int hShredEndOffset = shred.getHostRangeMarker().getEndOffset();
|
||||
int hShredStartOffset = shred.getHostRangeMarker().getStartOffset();
|
||||
Segment hostRangeMarker = shred.getHostRangeMarker();
|
||||
if (hostRangeMarker == null) continue;
|
||||
int hShredEndOffset = hostRangeMarker.getEndOffset();
|
||||
int hShredStartOffset = hostRangeMarker.getStartOffset();
|
||||
|
||||
int hShredStartLine = myDelegate.getLineNumber(hShredStartOffset);
|
||||
int hShredEndLine = myDelegate.getLineNumber(hShredEndOffset);
|
||||
@@ -131,17 +130,17 @@ public class DocumentWindowImpl extends UserDataHolderBase implements Disposable
|
||||
int[] pos = new int[2]; // pos[0] = curLine; pos[1] == offset;
|
||||
synchronized (myLock) {
|
||||
for (PsiLanguageInjectionHost.Shred shred : myShreds) {
|
||||
RangeMarker hostRange = shred.getHostRangeMarker();
|
||||
if (!hostRange.isValid()) continue;
|
||||
Segment hostRange = shred.getHostRangeMarker();
|
||||
if (hostRange == null) continue;
|
||||
|
||||
int found = countNewLinesIn(shred.prefix, pos, line);
|
||||
int found = countNewLinesIn(shred.getPrefix(), pos, line);
|
||||
if (found != -1) return found;
|
||||
|
||||
String text = hostText.substring(hostRange.getStartOffset(), hostRange.getEndOffset());
|
||||
found = countNewLinesIn(text, pos, line);
|
||||
if (found != -1) return found;
|
||||
|
||||
found = countNewLinesIn(shred.suffix, pos, line);
|
||||
found = countNewLinesIn(shred.getSuffix(), pos, line);
|
||||
if (found != -1) return found;
|
||||
}
|
||||
}
|
||||
@@ -187,11 +186,11 @@ public class DocumentWindowImpl extends UserDataHolderBase implements Disposable
|
||||
CharSequence hostText = myDelegate.getCharsSequence();
|
||||
synchronized (myLock) {
|
||||
for (PsiLanguageInjectionHost.Shred shred : myShreds) {
|
||||
RangeMarker hostRange = shred.getHostRangeMarker();
|
||||
if (hostRange.isValid()) {
|
||||
text.append(shred.prefix);
|
||||
Segment hostRange = shred.getHostRangeMarker();
|
||||
if (hostRange != null) {
|
||||
text.append(shred.getPrefix());
|
||||
text.append(hostText, hostRange.getStartOffset(), hostRange.getEndOffset());
|
||||
text.append(shred.suffix);
|
||||
text.append(shred.getSuffix());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -221,10 +220,11 @@ public class DocumentWindowImpl extends UserDataHolderBase implements Disposable
|
||||
int length = 0;
|
||||
synchronized (myLock) {
|
||||
for (PsiLanguageInjectionHost.Shred shred : myShreds) {
|
||||
RangeMarker hostRange = shred.getHostRangeMarker();
|
||||
length += shred.prefix.length();
|
||||
Segment hostRange = shred.getHostRangeMarker();
|
||||
if (hostRange == null) continue;
|
||||
length += shred.getPrefix().length();
|
||||
length += hostRange.getEndOffset() - hostRange.getStartOffset();
|
||||
length += shred.suffix.length();
|
||||
length += shred.getSuffix().length();
|
||||
}
|
||||
}
|
||||
return length;
|
||||
@@ -236,16 +236,16 @@ public class DocumentWindowImpl extends UserDataHolderBase implements Disposable
|
||||
String hostText = myDelegate.getText();
|
||||
synchronized (myLock) {
|
||||
for (PsiLanguageInjectionHost.Shred shred : myShreds) {
|
||||
String prefix = shred.prefix;
|
||||
String suffix = shred.suffix;
|
||||
String prefix = shred.getPrefix();
|
||||
String suffix = shred.getSuffix();
|
||||
lineNumber += StringUtil.getLineBreakCount(prefix.substring(0, Math.min(offset, prefix.length())));
|
||||
if (offset < prefix.length()) {
|
||||
return lineNumber;
|
||||
}
|
||||
offset -= prefix.length();
|
||||
|
||||
RangeMarker currentRange = shred.getHostRangeMarker();
|
||||
if (!currentRange.isValid()) continue;
|
||||
Segment currentRange = shred.getHostRangeMarker();
|
||||
if (currentRange == null) continue;
|
||||
int rangeLength = currentRange.getEndOffset() - currentRange.getStartOffset();
|
||||
String rangeText = hostText.substring(currentRange.getStartOffset(), currentRange.getEndOffset());
|
||||
|
||||
@@ -271,7 +271,8 @@ public class DocumentWindowImpl extends UserDataHolderBase implements Disposable
|
||||
public TextRange getHostRange(int hostOffset) {
|
||||
synchronized (myLock) {
|
||||
for (PsiLanguageInjectionHost.Shred shred : myShreds) {
|
||||
RangeMarker currentRange = shred.getHostRangeMarker();
|
||||
Segment currentRange = shred.getHostRangeMarker();
|
||||
if (currentRange == null) continue;
|
||||
TextRange textRange = ProperTextRange.create(currentRange);
|
||||
if (textRange.grown(1).contains(hostOffset)) return textRange;
|
||||
}
|
||||
@@ -282,8 +283,9 @@ public class DocumentWindowImpl extends UserDataHolderBase implements Disposable
|
||||
@Override
|
||||
public void insertString(final int offset, @NotNull CharSequence s) {
|
||||
synchronized (myLock) {
|
||||
LOG.assertTrue(offset >= myShreds.get(0).prefix.length(), myShreds.get(0).prefix);
|
||||
LOG.assertTrue(offset <= getTextLength() - myShreds.get(myShreds.size() - 1).suffix.length(), myShreds.get(myShreds.size() - 1).suffix);
|
||||
LOG.assertTrue(offset >= myShreds.get(0).getPrefix().length(), myShreds.get(0).getPrefix());
|
||||
LOG.assertTrue(offset <= getTextLength() - myShreds.get(myShreds.size() - 1).getSuffix().length(),
|
||||
myShreds.get(myShreds.size() - 1).getSuffix());
|
||||
}
|
||||
if (isOneLine()) {
|
||||
s = StringUtil.replace(s.toString(), "\n", "");
|
||||
@@ -303,11 +305,11 @@ public class DocumentWindowImpl extends UserDataHolderBase implements Disposable
|
||||
int offset = startOffset;
|
||||
int curRangeStart = 0;
|
||||
for (PsiLanguageInjectionHost.Shred shred : myShreds) {
|
||||
curRangeStart += shred.prefix.length();
|
||||
curRangeStart += shred.getPrefix().length();
|
||||
if (offset < curRangeStart) offset = curRangeStart;
|
||||
if (offset >= endOffset) break;
|
||||
RangeMarker hostRange = shred.getHostRangeMarker();
|
||||
if (!hostRange.isValid()) continue;
|
||||
Segment hostRange = shred.getHostRangeMarker();
|
||||
if (hostRange == null) continue;
|
||||
int hostRangeLength = hostRange.getEndOffset() - hostRange.getStartOffset();
|
||||
TextRange range = TextRange.from(curRangeStart, hostRangeLength);
|
||||
if (range.contains(offset)) {
|
||||
@@ -316,7 +318,7 @@ public class DocumentWindowImpl extends UserDataHolderBase implements Disposable
|
||||
offset = rangeToDelete.getEndOffset();
|
||||
}
|
||||
curRangeStart += hostRangeLength;
|
||||
curRangeStart += shred.suffix.length();
|
||||
curRangeStart += shred.getSuffix().length();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -357,23 +359,23 @@ public class DocumentWindowImpl extends UserDataHolderBase implements Disposable
|
||||
int curRangeStart = 0;
|
||||
for (int i = 0; i < myShreds.size(); i++) {
|
||||
PsiLanguageInjectionHost.Shred shred = myShreds.get(i);
|
||||
curRangeStart += shred.prefix.length();
|
||||
curRangeStart += shred.getPrefix().length();
|
||||
if (offset < curRangeStart) offset = curRangeStart;
|
||||
RangeMarker hostRange = shred.getHostRangeMarker();
|
||||
if (!hostRange.isValid()) continue;
|
||||
Segment hostRange = shred.getHostRangeMarker();
|
||||
if (hostRange == null) continue;
|
||||
int hostRangeLength = hostRange.getEndOffset() - hostRange.getStartOffset();
|
||||
TextRange range = TextRange.from(curRangeStart, hostRangeLength);
|
||||
if (range.contains(offset) || range.getEndOffset() == offset/* in case of inserting at the end*/) {
|
||||
TextRange rangeToModify = new TextRange(offset, Math.min(range.getEndOffset(), endOffset));
|
||||
TextRange hostRangeToModify = rangeToModify.shiftRight(hostRange.getStartOffset() - curRangeStart);
|
||||
CharSequence toReplace = i == myShreds.size() - 1 || range.getEndOffset() + shred.suffix.length() >= endOffset
|
||||
CharSequence toReplace = i == myShreds.size() - 1 || range.getEndOffset() + shred.getSuffix().length() >= endOffset
|
||||
? s : s.subSequence(0, Math.min(hostRangeToModify.getLength(), s.length()));
|
||||
s = toReplace == s ? "" : s.subSequence(toReplace.length(), s.length());
|
||||
hostRangesToModify.add(Pair.create(hostRangeToModify, toReplace));
|
||||
offset = rangeToModify.getEndOffset();
|
||||
}
|
||||
curRangeStart += hostRangeLength;
|
||||
curRangeStart += shred.suffix.length();
|
||||
curRangeStart += shred.getSuffix().length();
|
||||
if (curRangeStart >= endOffset) break;
|
||||
}
|
||||
}
|
||||
@@ -495,8 +497,8 @@ public class DocumentWindowImpl extends UserDataHolderBase implements Disposable
|
||||
@Override
|
||||
public void setText(@NotNull CharSequence text) {
|
||||
synchronized (myLock) {
|
||||
LOG.assertTrue(text.toString().startsWith(myShreds.get(0).prefix));
|
||||
LOG.assertTrue(text.toString().endsWith(myShreds.get(myShreds.size() - 1).suffix));
|
||||
LOG.assertTrue(text.toString().startsWith(myShreds.get(0).getPrefix()));
|
||||
LOG.assertTrue(text.toString().endsWith(myShreds.get(myShreds.size() - 1).getSuffix()));
|
||||
if (isOneLine()) {
|
||||
text = StringUtil.replace(text.toString(), "\n", "");
|
||||
}
|
||||
@@ -505,7 +507,8 @@ public class DocumentWindowImpl extends UserDataHolderBase implements Disposable
|
||||
for (int i = 0; i < changes.length; i++) {
|
||||
String change = changes[i];
|
||||
if (change != null) {
|
||||
RangeMarker hostRange = myShreds.get(i).getHostRangeMarker();
|
||||
Segment hostRange = myShreds.get(i).getHostRangeMarker();
|
||||
if (hostRange == null) continue;
|
||||
myDelegate.replaceString(hostRange.getStartOffset(), hostRange.getEndOffset(), change);
|
||||
}
|
||||
}
|
||||
@@ -514,14 +517,16 @@ public class DocumentWindowImpl extends UserDataHolderBase implements Disposable
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
public RangeMarker[] getHostRanges() {
|
||||
public Segment[] getHostRanges() {
|
||||
synchronized (myLock) {
|
||||
RangeMarker[] markers = new RangeMarker[myShreds.size()];
|
||||
for (int i = 0; i < myShreds.size(); i++) {
|
||||
PsiLanguageInjectionHost.Shred shred = myShreds.get(i);
|
||||
markers[i] = shred.getHostRangeMarker();
|
||||
List<Segment> markers = new ArrayList<Segment>(myShreds.size());
|
||||
for (PsiLanguageInjectionHost.Shred shred : myShreds) {
|
||||
Segment hostMarker = shred.getHostRangeMarker();
|
||||
if (hostMarker != null) {
|
||||
markers.add(hostMarker);
|
||||
}
|
||||
}
|
||||
return markers;
|
||||
return markers.isEmpty() ? Segment.EMPTY_ARRAY : markers.toArray(new Segment[markers.size()]);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -618,20 +623,20 @@ public class DocumentWindowImpl extends UserDataHolderBase implements Disposable
|
||||
@Override
|
||||
public int hostToInjected(int hostOffset) {
|
||||
synchronized (myLock) {
|
||||
if (hostOffset < myShreds.get(0).getHostRangeMarker().getStartOffset()) return myShreds.get(0).prefix.length();
|
||||
if (hostOffset < myShreds.get(0).getHostRangeMarker().getStartOffset()) return myShreds.get(0).getPrefix().length();
|
||||
int offset = 0;
|
||||
for (int i = 0; i < myShreds.size(); i++) {
|
||||
offset += myShreds.get(i).prefix.length();
|
||||
RangeMarker currentRange = myShreds.get(i).getHostRangeMarker();
|
||||
RangeMarker nextRange = i == myShreds.size() - 1 ? null : myShreds.get(i + 1).getHostRangeMarker();
|
||||
offset += myShreds.get(i).getPrefix().length();
|
||||
Segment currentRange = myShreds.get(i).getHostRangeMarker();
|
||||
Segment nextRange = i == myShreds.size() - 1 ? null : myShreds.get(i + 1).getHostRangeMarker();
|
||||
if (nextRange == null || hostOffset < nextRange.getStartOffset()) {
|
||||
if (hostOffset >= currentRange.getEndOffset()) hostOffset = currentRange.getEndOffset();
|
||||
return offset + hostOffset - currentRange.getStartOffset();
|
||||
}
|
||||
offset += currentRange.getEndOffset() - currentRange.getStartOffset();
|
||||
offset += myShreds.get(i).suffix.length();
|
||||
offset += myShreds.get(i).getSuffix().length();
|
||||
}
|
||||
return getTextLength() - myShreds.get(myShreds.size() - 1).suffix.length();
|
||||
return getTextLength() - myShreds.get(myShreds.size() - 1).getSuffix().length();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -655,11 +660,12 @@ public class DocumentWindowImpl extends UserDataHolderBase implements Disposable
|
||||
|
||||
private int injectedToHost(int offset, boolean preferLeftFragment) {
|
||||
synchronized (myLock) {
|
||||
if (offset < myShreds.get(0).prefix.length()) return myShreds.get(0).getHostRangeMarker().getStartOffset();
|
||||
if (offset < myShreds.get(0).getPrefix().length()) return myShreds.get(0).getHostRangeMarker().getStartOffset();
|
||||
int prevEnd = 0;
|
||||
for (int i = 0; i < myShreds.size(); i++) {
|
||||
RangeMarker currentRange = myShreds.get(i).getHostRangeMarker();
|
||||
offset -= myShreds.get(i).prefix.length();
|
||||
Segment currentRange = myShreds.get(i).getHostRangeMarker();
|
||||
if (currentRange == null) continue;
|
||||
offset -= myShreds.get(i).getPrefix().length();
|
||||
int length = currentRange.getEndOffset() - currentRange.getStartOffset();
|
||||
if (offset < 0) {
|
||||
return preferLeftFragment ? prevEnd : currentRange.getStartOffset() - 1;
|
||||
@@ -671,7 +677,7 @@ public class DocumentWindowImpl extends UserDataHolderBase implements Disposable
|
||||
return currentRange.getStartOffset() + offset;
|
||||
}
|
||||
offset -= length;
|
||||
offset -= myShreds.get(i).suffix.length();
|
||||
offset -= myShreds.get(i).getSuffix().length();
|
||||
prevEnd = currentRange.getEndOffset();
|
||||
}
|
||||
return myShreds.get(myShreds.size() - 1).getHostRangeMarker().getEndOffset();
|
||||
@@ -712,8 +718,8 @@ public class DocumentWindowImpl extends UserDataHolderBase implements Disposable
|
||||
synchronized (myLock) {
|
||||
if (end - start > myShreds.get(0).getHostRangeMarker().getEndOffset() - myShreds.get(0).getHostRangeMarker().getStartOffset()) return false;
|
||||
for (PsiLanguageInjectionHost.Shred shred : myShreds) {
|
||||
RangeMarker hostRange = shred.getHostRangeMarker();
|
||||
if (!hostRange.isValid()) continue;
|
||||
Segment hostRange = shred.getHostRangeMarker();
|
||||
if (hostRange == null) continue;
|
||||
TextRange textRange = ProperTextRange.create(hostRange);
|
||||
if (textRange.contains(new ProperTextRange(start, end))) return true;
|
||||
}
|
||||
@@ -730,8 +736,9 @@ public class DocumentWindowImpl extends UserDataHolderBase implements Disposable
|
||||
synchronized (myLock) {
|
||||
int offset = 0;
|
||||
for (PsiLanguageInjectionHost.Shred shred : myShreds) {
|
||||
RangeMarker hostRange = shred.getHostRangeMarker();
|
||||
offset += shred.prefix.length();
|
||||
Segment hostRange = shred.getHostRangeMarker();
|
||||
if (hostRange == null) continue;
|
||||
offset += shred.getPrefix().length();
|
||||
int length = hostRange.getEndOffset() - hostRange.getStartOffset();
|
||||
TextRange intersection = new ProperTextRange(offset, offset + length).intersection(rangeToEdit);
|
||||
if (intersection != null) {
|
||||
@@ -741,7 +748,7 @@ public class DocumentWindowImpl extends UserDataHolderBase implements Disposable
|
||||
endOffset = intersection.getEndOffset();
|
||||
}
|
||||
offset += length;
|
||||
offset += shred.suffix.length();
|
||||
offset += shred.getSuffix().length();
|
||||
}
|
||||
}
|
||||
if (startOffset == -1) return null;
|
||||
@@ -760,8 +767,8 @@ public class DocumentWindowImpl extends UserDataHolderBase implements Disposable
|
||||
for (int i = 0; i < result.length; i++) {
|
||||
String change = result[i];
|
||||
if (change == null) continue;
|
||||
String prefix = myShreds.get(i).prefix;
|
||||
String suffix = myShreds.get(i).suffix;
|
||||
String prefix = myShreds.get(i).getPrefix();
|
||||
String suffix = myShreds.get(i).getSuffix();
|
||||
assert change.startsWith(prefix) : change + "/" + prefix;
|
||||
assert change.endsWith(suffix) : change + "/" + suffix;
|
||||
result[i] = StringUtil.trimEnd(StringUtil.trimStart(change, prefix), suffix);
|
||||
@@ -773,9 +780,9 @@ public class DocumentWindowImpl extends UserDataHolderBase implements Disposable
|
||||
private String getRangeText(String hostText, int hostNum) {
|
||||
synchronized (myLock) {
|
||||
PsiLanguageInjectionHost.Shred shred = myShreds.get(hostNum);
|
||||
return shred.prefix +
|
||||
return shred.getPrefix() +
|
||||
hostText.substring(shred.getHostRangeMarker().getStartOffset(), shred.getHostRangeMarker().getEndOffset()) +
|
||||
shred.suffix;
|
||||
shred.getSuffix();
|
||||
}
|
||||
}
|
||||
private void calculateMinEditSequence(String hostText, String newText, String[] result, int i, int j) {
|
||||
@@ -797,8 +804,8 @@ public class DocumentWindowImpl extends UserDataHolderBase implements Disposable
|
||||
return;
|
||||
}
|
||||
if (i+1 == j) {
|
||||
String suffix = myShreds.get(i).suffix;
|
||||
String prefix = myShreds.get(j).prefix;
|
||||
String suffix = myShreds.get(i).getSuffix();
|
||||
String prefix = myShreds.get(j).getPrefix();
|
||||
String separator = suffix + prefix;
|
||||
if (!separator.isEmpty()) {
|
||||
int sep = newText.indexOf(separator);
|
||||
@@ -843,12 +850,12 @@ public class DocumentWindowImpl extends UserDataHolderBase implements Disposable
|
||||
for (int i = 0; i < shreds.size(); i++) {
|
||||
PsiLanguageInjectionHost.Shred shred = shreds.get(i);
|
||||
PsiLanguageInjectionHost.Shred otherShred = otherShreds.get(i);
|
||||
if (!shred.prefix.equals(otherShred.prefix)) return false;
|
||||
if (!shred.suffix.equals(otherShred.suffix)) return false;
|
||||
if (!shred.getPrefix().equals(otherShred.getPrefix())) return false;
|
||||
if (!shred.getSuffix().equals(otherShred.getSuffix())) return false;
|
||||
|
||||
RangeMarker hostRange = shred.getHostRangeMarker();
|
||||
RangeMarker other = otherShred.getHostRangeMarker();
|
||||
if (hostRange.getStartOffset() != other.getStartOffset()) return false;
|
||||
Segment hostRange = shred.getHostRangeMarker();
|
||||
Segment other = otherShred.getHostRangeMarker();
|
||||
if (hostRange == null || other == null || hostRange.getStartOffset() != other.getStartOffset()) return false;
|
||||
if (hostRange.getEndOffset() != other.getEndOffset()) return false;
|
||||
}
|
||||
return true;
|
||||
@@ -880,10 +887,7 @@ public class DocumentWindowImpl extends UserDataHolderBase implements Disposable
|
||||
@Override
|
||||
public void dispose() {
|
||||
synchronized (myLock) {
|
||||
for (PsiLanguageInjectionHost.Shred shred : myShreds) {
|
||||
RangeMarker rangeMarker = shred.getHostRangeMarker();
|
||||
rangeMarker.dispose();
|
||||
}
|
||||
myShreds.dispose();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+2
-2
@@ -70,8 +70,8 @@ public abstract class InjectedLanguageBlockBuilder {
|
||||
canProcessFragment(childText.substring(textRange.getEndOffset()), injectionHost))) {
|
||||
injectedFile[0] = injectedPsi;
|
||||
injectedRangeInsideHost.set(textRange);
|
||||
prefixLength.set(shred.prefix != null ? shred.prefix.length() : 0);
|
||||
suffixLength.set(shred.suffix != null ? shred.suffix.length() : 0);
|
||||
prefixLength.set(shred.getPrefix() != null ? shred.getPrefix().length() : 0);
|
||||
suffixLength.set(shred.getSuffix() != null ? shred.getSuffix().length() : 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+6
-15
@@ -21,16 +21,15 @@ import com.intellij.injected.editor.DocumentWindowImpl;
|
||||
import com.intellij.injected.editor.VirtualFileWindow;
|
||||
import com.intellij.lang.Language;
|
||||
import com.intellij.openapi.editor.Document;
|
||||
import com.intellij.openapi.editor.RangeMarker;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.util.Ref;
|
||||
import com.intellij.openapi.util.Segment;
|
||||
import com.intellij.openapi.util.TextRange;
|
||||
import com.intellij.openapi.util.text.StringUtil;
|
||||
import com.intellij.openapi.vfs.VirtualFile;
|
||||
import com.intellij.psi.*;
|
||||
import com.intellij.psi.impl.FreeThreadedFileViewProvider;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@@ -55,7 +54,7 @@ public class InjectedFileViewProvider extends SingleRootFileViewProvider impleme
|
||||
@NotNull Language language) {
|
||||
super(psiManager, (VirtualFile)virtualFile, true, language);
|
||||
myDocumentWindow = documentWindow;
|
||||
myProject = documentWindow.getShreds().get(0).host.getProject();
|
||||
myProject = documentWindow.getShreds().get(0).getHost().getProject();
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -73,10 +72,11 @@ public class InjectedFileViewProvider extends SingleRootFileViewProvider impleme
|
||||
String change = changes[i];
|
||||
if (change != null) {
|
||||
PsiLanguageInjectionHost.Shred shred = shreds.get(i);
|
||||
PsiLanguageInjectionHost host = shred.host;
|
||||
PsiLanguageInjectionHost host = shred.getHost();
|
||||
TextRange rangeInsideHost = shred.getRangeInsideHost();
|
||||
String newHostText = StringUtil.replaceSubstring(host.getText(), rangeInsideHost, change);
|
||||
shred.host = host.updateText(newHostText);
|
||||
//shred.host =
|
||||
host.updateText(newHostText);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -89,7 +89,7 @@ public class InjectedFileViewProvider extends SingleRootFileViewProvider impleme
|
||||
PsiFile hostFile = documentManager.getPsiFile(hostDocument);
|
||||
final Language hostFileLanguage = getPsi(getBaseLanguage()).getContext().getContainingFile().getLanguage();
|
||||
PsiFile hostPsiFileCopy = (PsiFile)hostFile.copy();
|
||||
RangeMarker firstTextRange = oldDocumentWindow.getHostRanges()[0];
|
||||
Segment firstTextRange = oldDocumentWindow.getHostRanges()[0];
|
||||
PsiElement elementCopy = hostPsiFileCopy.getViewProvider().findElementAt(firstTextRange.getStartOffset(), hostFileLanguage);
|
||||
assert elementCopy != null;
|
||||
final Ref<FileViewProvider> provider = new Ref<FileViewProvider>();
|
||||
@@ -105,15 +105,6 @@ public class InjectedFileViewProvider extends SingleRootFileViewProvider impleme
|
||||
return provider.get();
|
||||
}
|
||||
|
||||
@Override
|
||||
@Nullable
|
||||
protected PsiFile getPsiInner(Language target) {
|
||||
// when FileManager rebuilds file map, all files temporarily become invalid, so this check is doomed
|
||||
PsiFile file = super.getPsiInner(target);
|
||||
//if (file == null || file.getContext() == null) return null;
|
||||
return file;
|
||||
}
|
||||
|
||||
// returns true if shreds were set, false if old ones were reused
|
||||
boolean setShreds(@NotNull Place newShreds, @NotNull Project project) {
|
||||
synchronized (myLock) {
|
||||
|
||||
+10
-7
@@ -32,7 +32,6 @@ import com.intellij.openapi.application.ApplicationManager;
|
||||
import com.intellij.openapi.application.ex.ApplicationManagerEx;
|
||||
import com.intellij.openapi.diagnostic.Logger;
|
||||
import com.intellij.openapi.editor.Document;
|
||||
import com.intellij.openapi.editor.RangeMarker;
|
||||
import com.intellij.openapi.extensions.ExtensionPoint;
|
||||
import com.intellij.openapi.extensions.ExtensionPointListener;
|
||||
import com.intellij.openapi.extensions.Extensions;
|
||||
@@ -43,6 +42,7 @@ import com.intellij.openapi.project.DumbService;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.util.Key;
|
||||
import com.intellij.openapi.util.ProperTextRange;
|
||||
import com.intellij.openapi.util.Segment;
|
||||
import com.intellij.openapi.util.TextRange;
|
||||
import com.intellij.openapi.vfs.VirtualFile;
|
||||
import com.intellij.psi.*;
|
||||
@@ -58,6 +58,7 @@ import org.jetbrains.annotations.TestOnly;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.concurrent.ConcurrentMap;
|
||||
import java.util.concurrent.CopyOnWriteArrayList;
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
|
||||
/**
|
||||
@@ -128,7 +129,8 @@ public class InjectedLanguageManagerImpl extends InjectedLanguageManager impleme
|
||||
final PsiFile hostPsiFile = documentManager.getCachedPsiFile(hostDocument);
|
||||
if (hostPsiFile == null) return;
|
||||
|
||||
final List<DocumentWindow> injected = InjectedLanguageUtil.getCachedInjectedDocuments(hostPsiFile);
|
||||
final CopyOnWriteArrayList<DocumentWindow> injected =
|
||||
(CopyOnWriteArrayList<DocumentWindow>)InjectedLanguageUtil.getCachedInjectedDocuments(hostPsiFile);
|
||||
if (injected.isEmpty()) return;
|
||||
|
||||
if (myProgress.isCanceled()) {
|
||||
@@ -143,8 +145,9 @@ public class InjectedLanguageManagerImpl extends InjectedLanguageManager impleme
|
||||
if (indicator != null && indicator.isCanceled()) return false;
|
||||
if (documentManager.isUncommited(hostDocument) || !hostPsiFile.isValid()) return false; // will be committed later
|
||||
|
||||
RangeMarker rangeMarker = documentWindow.getHostRanges()[0];
|
||||
PsiElement element = rangeMarker.isValid() ? hostPsiFile.findElementAt(rangeMarker.getStartOffset()) : null;
|
||||
Segment[] ranges = documentWindow.getHostRanges();
|
||||
Segment rangeMarker = ranges.length > 0 ? ranges[0] : null;
|
||||
PsiElement element = rangeMarker == null ? null : hostPsiFile.findElementAt(rangeMarker.getStartOffset());
|
||||
if (element == null) {
|
||||
synchronized (PsiLock.LOCK) {
|
||||
injected.remove(documentWindow);
|
||||
@@ -166,7 +169,7 @@ public class InjectedLanguageManagerImpl extends InjectedLanguageManager impleme
|
||||
}
|
||||
else if (stillInjectedDocument[0] != documentWindow) {
|
||||
injected.remove(documentWindow);
|
||||
injected.add(stillInjectedDocument[0]);
|
||||
injected.addIfAbsent(stillInjectedDocument[0]);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -334,7 +337,7 @@ public class InjectedLanguageManagerImpl extends InjectedLanguageManager impleme
|
||||
int count = 0;
|
||||
int offset = 0;
|
||||
for (PsiLanguageInjectionHost.Shred shred : shreds) {
|
||||
TextRange encodedRange = TextRange.from(offset + shred.prefix.length(), shred.getRangeInsideHost().getLength());
|
||||
TextRange encodedRange = TextRange.from(offset + shred.getPrefix().length(), shred.getRangeInsideHost().getLength());
|
||||
TextRange intersection = encodedRange.intersection(rangeToEdit);
|
||||
if (intersection != null) {
|
||||
count++;
|
||||
@@ -364,7 +367,7 @@ public class InjectedLanguageManagerImpl extends InjectedLanguageManager impleme
|
||||
((List<TextRange>)result).add(intersection);
|
||||
}
|
||||
}
|
||||
offset += shred.prefix.length() + shred.getRangeInsideHost().getLength() + shred.suffix.length();
|
||||
offset += shred.getPrefix().length() + shred.getRangeInsideHost().getLength() + shred.getSuffix().length();
|
||||
}
|
||||
return count == 0 ? Collections.<TextRange>emptyList() : count == 1 ? Collections.singletonList((TextRange)result) : (List<TextRange>)result;
|
||||
}
|
||||
|
||||
+3
-3
@@ -85,7 +85,7 @@ public class InjectedLanguageUtil {
|
||||
@Override
|
||||
public void visit(@NotNull PsiFile injectedPsi, @NotNull List<PsiLanguageInjectionHost.Shred> places) {
|
||||
for (PsiLanguageInjectionHost.Shred place : places) {
|
||||
if (place.host == inTree) {
|
||||
if (place.getHost() == inTree) {
|
||||
result.add(new Pair<PsiElement, TextRange>(injectedPsi, place.getRangeInsideHost()));
|
||||
}
|
||||
}
|
||||
@@ -238,7 +238,7 @@ public class InjectedLanguageUtil {
|
||||
for (Pair<Place, PsiFile> pair : places) {
|
||||
Place place = pair.first;
|
||||
for (PsiLanguageInjectionHost.Shred shred : place) {
|
||||
if (shred.host.getTextRange().intersects(elementRange)) {
|
||||
if (shred.getHost().getTextRange().intersects(elementRange)) {
|
||||
if (place.isValid()) break nextParent;
|
||||
}
|
||||
}
|
||||
@@ -310,7 +310,7 @@ public class InjectedLanguageUtil {
|
||||
@Override
|
||||
public void visit(@NotNull PsiFile injectedPsi, @NotNull List<PsiLanguageInjectionHost.Shred> places) {
|
||||
for (PsiLanguageInjectionHost.Shred place : places) {
|
||||
TextRange hostRange = place.host.getTextRange();
|
||||
TextRange hostRange = place.getHost().getTextRange();
|
||||
if (hostRange.cutOut(place.getRangeInsideHost()).grown(1).contains(hostOffset)) {
|
||||
DocumentWindowImpl document = (DocumentWindowImpl)documentManager.getCachedDocument(injectedPsi);
|
||||
if (document == null) return;
|
||||
|
||||
@@ -74,14 +74,14 @@ class LeafPatcher extends RecursiveTreeElementWalkingVisitor {
|
||||
|
||||
private StringBuilder constructTextFromHostPSI(int startOffset, int endOffset) {
|
||||
PsiLanguageInjectionHost.Shred current = myShreds.get(shredNo);
|
||||
if (hostText == null) hostText = current.host.getText();
|
||||
if (hostText == null) hostText = current.getHost().getText();
|
||||
StringBuilder text = new StringBuilder(endOffset-startOffset);
|
||||
while (startOffset < endOffset) {
|
||||
TextRange shredRange = current.range;
|
||||
String prefix = current.prefix;
|
||||
TextRange shredRange = current.getRange();
|
||||
String prefix = current.getPrefix();
|
||||
if (startOffset >= shredRange.getEndOffset()) {
|
||||
current = myShreds.get(++shredNo);
|
||||
hostText = current.host.getText();
|
||||
hostText = current.getHost().getText();
|
||||
continue;
|
||||
}
|
||||
assert startOffset >= shredRange.getStartOffset();
|
||||
@@ -93,7 +93,7 @@ class LeafPatcher extends RecursiveTreeElementWalkingVisitor {
|
||||
continue;
|
||||
}
|
||||
|
||||
String suffix = current.suffix;
|
||||
String suffix = current.getSuffix();
|
||||
if (startOffset < shredRange.getEndOffset() - suffix.length()) {
|
||||
// inside host body, cut out from the host text
|
||||
int startOffsetInHost = myEscapers.get(shredNo).getOffsetInHost(startOffset - shredRange.getStartOffset() - prefix.length(), current.getRangeInsideHost());
|
||||
|
||||
+11
-18
@@ -53,7 +53,6 @@ import com.intellij.psi.impl.source.tree.TreeUtil;
|
||||
import com.intellij.psi.tree.IElementType;
|
||||
import com.intellij.psi.util.PsiTreeUtil;
|
||||
import com.intellij.psi.util.PsiUtilCore;
|
||||
import com.intellij.util.ArrayUtil;
|
||||
import com.intellij.util.SmartList;
|
||||
import org.jetbrains.annotations.NonNls;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
@@ -183,7 +182,7 @@ public class MultiHostRegistrarImpl implements MultiHostRegistrar, ModificationT
|
||||
RangeMarker relevantMarker = myHostDocument.createRangeMarker(relevantRangeInHost);
|
||||
relevantMarker.setGreedyToLeft(true);
|
||||
relevantMarker.setGreedyToRight(true);
|
||||
shreds.add(new PsiLanguageInjectionHost.Shred(host, relevantMarker, prefix, suffix, new ProperTextRange(startOffset, endOffset)));
|
||||
shreds.add(new ShredImpl(host, myHostPsiFile, relevantMarker, prefix, suffix, new ProperTextRange(startOffset, endOffset)));
|
||||
return this;
|
||||
}
|
||||
|
||||
@@ -193,8 +192,9 @@ public class MultiHostRegistrarImpl implements MultiHostRegistrar, ModificationT
|
||||
if (shreds.isEmpty()) {
|
||||
throw new IllegalStateException("Seems you haven't called addPlace()");
|
||||
}
|
||||
PsiDocumentManager documentManager = PsiDocumentManager.getInstance(myProject);
|
||||
assert ArrayUtil.indexOf(documentManager.getUncommittedDocuments(), myHostDocument) == -1 : "document is uncommitted: "+myHostDocument;
|
||||
PsiDocumentManagerImpl documentManager = (PsiDocumentManagerImpl)PsiDocumentManager.getInstance(myProject);
|
||||
//todo restore
|
||||
//assert !documentManager.getUncommittedDocumentsUnsafe().contains(myHostDocument) : "document is uncommitted: "+myHostDocument;
|
||||
|
||||
Place place = new Place(shreds);
|
||||
DocumentWindowImpl documentWindow = new DocumentWindowImpl(myHostDocument, isOneLineEditor, place);
|
||||
@@ -218,7 +218,7 @@ public class MultiHostRegistrarImpl implements MultiHostRegistrar, ModificationT
|
||||
assert parserDefinition != null : "Parser definition for language "+myLanguage+" is null";
|
||||
PsiFile psiFile = parserDefinition.createFile(viewProvider);
|
||||
|
||||
SmartPsiElementPointer<PsiLanguageInjectionHost> pointer = createHostSmartPointer(shreds.get(0).host, myHostPsiFile);
|
||||
SmartPsiElementPointer<PsiLanguageInjectionHost> pointer = ((ShredImpl)shreds.get(0)).getSmartPointer();
|
||||
|
||||
synchronized (PsiLock.LOCK) {
|
||||
final ASTNode parsedNode = keepTreeFromChameleoningBack(psiFile);
|
||||
@@ -334,7 +334,7 @@ public class MultiHostRegistrarImpl implements MultiHostRegistrar, ModificationT
|
||||
private void assertEverythingIsAllright(PsiDocumentManager documentManager, DocumentWindowImpl documentWindow, PsiFile psiFile) {
|
||||
boolean isAncestor = false;
|
||||
for (PsiLanguageInjectionHost.Shred shred : shreds) {
|
||||
PsiLanguageInjectionHost host = shred.host;
|
||||
PsiLanguageInjectionHost host = shred.getHost();
|
||||
isAncestor |= PsiTreeUtil.isAncestor(myContextElement, host, false);
|
||||
}
|
||||
assert isAncestor : exceptionContext(myContextElement + " must be the parent of at least one of injection hosts");
|
||||
@@ -355,12 +355,6 @@ public class MultiHostRegistrarImpl implements MultiHostRegistrar, ModificationT
|
||||
result.add(Pair.create(place, psiFile));
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private static <T extends PsiLanguageInjectionHost> SmartPsiElementPointer<T> createHostSmartPointer(@NotNull T host, @NotNull PsiFile hostPsiFile) {
|
||||
return hostPsiFile.isPhysical()
|
||||
? SmartPointerManager.getInstance(host.getProject()).createSmartPsiElementPointer(host, hostPsiFile)
|
||||
: new IdentitySmartPointer<T>(host, hostPsiFile);
|
||||
}
|
||||
|
||||
private static void patchLeafs(ASTNode parsedNode, List<LiteralTextEscaper<? extends PsiLanguageInjectionHost>> escapers, Place shreds) {
|
||||
LeafPatcher patcher = new LeafPatcher(shreds, escapers);
|
||||
@@ -373,7 +367,7 @@ public class MultiHostRegistrarImpl implements MultiHostRegistrar, ModificationT
|
||||
"\nLeaf texts concatenated:'"+ patcher.catLeafs +"';" +
|
||||
"\nFile root: "+parsedNode+
|
||||
"\nLanguage: "+parsedNode.getPsi().getLanguage()+
|
||||
"\nHost file: "+shreds.get(0).host.getContainingFile().getVirtualFile()
|
||||
"\nHost file: "+ shreds.get(0).getHost().getContainingFile().getVirtualFile()
|
||||
;
|
||||
for (Map.Entry<LeafElement, String> entry : patcher.newTexts.entrySet()) {
|
||||
LeafElement leaf = entry.getKey();
|
||||
@@ -396,7 +390,6 @@ public class MultiHostRegistrarImpl implements MultiHostRegistrar, ModificationT
|
||||
DocumentWindowImpl oldDocument = (DocumentWindowImpl)injected.get(i);
|
||||
final PsiFileImpl oldFile = (PsiFileImpl)documentManager.getCachedPsiFile(oldDocument);
|
||||
FileViewProvider viewProvider;
|
||||
|
||||
if (oldFile == null ||
|
||||
!oldFile.isValid() ||
|
||||
!((viewProvider = oldFile.getViewProvider()) instanceof InjectedFileViewProvider) ||
|
||||
@@ -472,13 +465,13 @@ public class MultiHostRegistrarImpl implements MultiHostRegistrar, ModificationT
|
||||
if (range.getStartOffset() >= shredEndOffset) {
|
||||
hostNum++;
|
||||
PsiLanguageInjectionHost.Shred shred = shreds.get(hostNum);
|
||||
shredEndOffset = shred.range.getEndOffset();
|
||||
shredEndOffset = shred.getRange().getEndOffset();
|
||||
prevHostEndOffset = range.getStartOffset();
|
||||
host = shred.host;
|
||||
host = shred.getHost();
|
||||
escaper = escapers.get(hostNum);
|
||||
rangeInsideHost = shred.getRangeInsideHost();
|
||||
prefixLength = shred.prefix.length();
|
||||
suffixLength = shred.suffix.length();
|
||||
prefixLength = shred.getPrefix().length();
|
||||
suffixLength = shred.getSuffix().length();
|
||||
}
|
||||
//in prefix/suffix or spills over to next fragment
|
||||
if (range.getStartOffset() < prevHostEndOffset + prefixLength) {
|
||||
|
||||
@@ -41,7 +41,7 @@ public class Place extends SmartList<PsiLanguageInjectionHost.Shred> {
|
||||
|
||||
public void dispose() {
|
||||
for (PsiLanguageInjectionHost.Shred shred : this) {
|
||||
shred.getHostRangeMarker().dispose();
|
||||
shred.dispose();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,146 @@
|
||||
/*
|
||||
* Copyright 2000-2012 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.intellij.psi.impl.source.tree.injected;
|
||||
|
||||
import com.intellij.openapi.editor.RangeMarker;
|
||||
import com.intellij.openapi.util.ProperTextRange;
|
||||
import com.intellij.openapi.util.Segment;
|
||||
import com.intellij.openapi.util.TextRange;
|
||||
import com.intellij.psi.*;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
class ShredImpl implements PsiLanguageInjectionHost.Shred {
|
||||
private final RangeMarker relevantRangeInHost;
|
||||
private final SmartPsiElementPointer<PsiLanguageInjectionHost> hostElementPointer;
|
||||
private final TextRange range; // range in (decoded) PSI
|
||||
private final String prefix;
|
||||
private final String suffix;
|
||||
|
||||
ShredImpl(@NotNull PsiLanguageInjectionHost host,
|
||||
@NotNull PsiFile hostPsiFile,
|
||||
@NotNull final RangeMarker relevantRangeInHost,
|
||||
@NotNull String prefix,
|
||||
@NotNull String suffix,
|
||||
@NotNull TextRange range) {
|
||||
hostElementPointer = createHostSmartPointer(host, hostPsiFile);
|
||||
this.relevantRangeInHost = relevantRangeInHost;
|
||||
this.prefix = prefix;
|
||||
this.suffix = suffix;
|
||||
this.range = range;
|
||||
assert isValid();
|
||||
assert relevantRangeInHost.isValid();
|
||||
}
|
||||
|
||||
public SmartPsiElementPointer<PsiLanguageInjectionHost> getSmartPointer() {
|
||||
return hostElementPointer;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private static <T extends PsiLanguageInjectionHost> SmartPsiElementPointer<T> createHostSmartPointer(@NotNull T host,
|
||||
@NotNull PsiFile hostPsiFile) {
|
||||
return hostPsiFile.isPhysical()
|
||||
? SmartPointerManager.getInstance(hostPsiFile.getProject()).createSmartPsiElementPointer(host, hostPsiFile)
|
||||
: new IdentitySmartPointer<T>(host, hostPsiFile);
|
||||
}
|
||||
|
||||
@Override
|
||||
@Nullable("returns null when the host document marker is invalid")
|
||||
public Segment getHostRangeMarker() {
|
||||
return relevantRangeInHost;
|
||||
}
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
public TextRange getRangeInsideHost() {
|
||||
TextRange hostTextRange = getHost().getTextRange();
|
||||
ProperTextRange textRange =
|
||||
relevantRangeInHost.isValid() ? new ProperTextRange(relevantRangeInHost.getStartOffset(), relevantRangeInHost.getEndOffset()) : null;
|
||||
textRange = textRange == null ? null : textRange.intersection(hostTextRange);
|
||||
if (textRange == null) return new ProperTextRange(0, hostTextRange.getLength());
|
||||
return textRange.shiftRight(-hostTextRange.getStartOffset());
|
||||
}
|
||||
|
||||
@SuppressWarnings({"HardCodedStringLiteral"})
|
||||
public String toString() {
|
||||
return "Shred " + getHost().getTextRange() + ": " + getHost() +
|
||||
" Inhost range: " +
|
||||
(relevantRangeInHost.isValid() ? "" : "!") +
|
||||
"(" +
|
||||
relevantRangeInHost.getStartOffset() +
|
||||
"," +
|
||||
relevantRangeInHost.getEndOffset() +
|
||||
");" +
|
||||
" PSI range: " +
|
||||
range;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isValid() {
|
||||
PsiLanguageInjectionHost host = getHost();
|
||||
return relevantRangeInHost.isValid() && host != null && host.isValid();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) return true;
|
||||
if (o == null || getClass() != o.getClass()) return false;
|
||||
|
||||
PsiLanguageInjectionHost.Shred shred = (PsiLanguageInjectionHost.Shred)o;
|
||||
|
||||
PsiLanguageInjectionHost host = getHost();
|
||||
return host != null &&
|
||||
host.equals(shred.getHost()) &&
|
||||
prefix.equals(shred.getPrefix()) &&
|
||||
suffix.equals(shred.getSuffix()) &&
|
||||
range.equals(shred.getRange()) &&
|
||||
TextRange.create(relevantRangeInHost).equals(TextRange.create(shred.getHostRangeMarker()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return range.hashCode();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dispose() {
|
||||
relevantRangeInHost.dispose();
|
||||
}
|
||||
|
||||
@Override
|
||||
@Nullable
|
||||
public PsiLanguageInjectionHost getHost() {
|
||||
return hostElementPointer.getElement();
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public TextRange getRange() {
|
||||
return range;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public String getPrefix() {
|
||||
return prefix;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public String getSuffix() {
|
||||
return suffix;
|
||||
}
|
||||
}
|
||||
@@ -19,6 +19,7 @@ package com.intellij.openapi.util;
|
||||
* User: cdr
|
||||
*/
|
||||
public interface Segment {
|
||||
Segment[] EMPTY_ARRAY = new Segment[0];
|
||||
int getStartOffset();
|
||||
int getEndOffset();
|
||||
}
|
||||
|
||||
@@ -112,6 +112,10 @@ public class TextRange implements Segment, Serializable {
|
||||
return create(segment.getStartOffset(), segment.getEndOffset());
|
||||
}
|
||||
|
||||
public static boolean areSegmentsEqual(@NotNull Segment segment1, @NotNull Segment segment2) {
|
||||
return segment1.getStartOffset() == segment2.getStartOffset()
|
||||
&& segment1.getEndOffset() == segment2.getEndOffset();
|
||||
}
|
||||
@NotNull
|
||||
public String replace(@NotNull String original, @NotNull String replacement) {
|
||||
String beginning = original.substring(0, getStartOffset());
|
||||
|
||||
+5
-4
@@ -176,7 +176,7 @@ public class QuickEditAction implements IntentionAction, LowPriorityAction {
|
||||
final String text = InjectedLanguageManager.getInstance(project).getUnescapedText(injectedFile);
|
||||
final String newFileName =
|
||||
StringUtil.notNullize(language.getDisplayName(), "Injected") + " Fragment " + "(" +
|
||||
origFile.getName() + ":" + shreds.get(0).host.getTextRange().getStartOffset() + ")" + "." + fileType.getDefaultExtension();
|
||||
origFile.getName() + ":" + shreds.get(0).getHost().getTextRange().getStartOffset() + ")" + "." + fileType.getDefaultExtension();
|
||||
myNewFile = factory.createFileFromText(newFileName, language, text, true, true);
|
||||
myNewVirtualFile = (LightVirtualFile)myNewFile.getVirtualFile();
|
||||
assert myNewVirtualFile != null;
|
||||
@@ -296,11 +296,12 @@ public class QuickEditAction implements IntentionAction, LowPriorityAction {
|
||||
final SmartPointerManager smartPointerManager = SmartPointerManager.getInstance(myProject);
|
||||
for (PsiLanguageInjectionHost.Shred shred : shreds) {
|
||||
final RangeMarker rangeMarker = myNewDocument
|
||||
.createRangeMarker(shred.range.getStartOffset() + shred.prefix.length(), shred.range.getEndOffset() - shred.suffix.length());
|
||||
.createRangeMarker(
|
||||
shred.getRange().getStartOffset() + shred.getPrefix().length(), shred.getRange().getEndOffset() - shred.getSuffix().length());
|
||||
final TextRange rangeInsideHost = shred.getRangeInsideHost();
|
||||
final RangeMarker origMarker =
|
||||
myOrigDocument.createRangeMarker(rangeInsideHost.shiftRight(shred.host.getTextRange().getStartOffset()));
|
||||
myMarkers.put(smartPointerManager.createSmartPsiElementPointer(shred.host), Pair.create(origMarker, rangeMarker));
|
||||
myOrigDocument.createRangeMarker(rangeInsideHost.shiftRight(shred.getHost().getTextRange().getStartOffset()));
|
||||
myMarkers.put(smartPointerManager.createSmartPsiElementPointer(shred.getHost()), Pair.create(origMarker, rangeMarker));
|
||||
}
|
||||
for (Pair<RangeMarker, RangeMarker> markers : myMarkers.values()) {
|
||||
markers.first.setGreedyToLeft(true);
|
||||
|
||||
Reference in New Issue
Block a user