下面列出了com.intellij.psi.formatter.DocumentBasedFormattingModel#com.intellij.injected.editor.DocumentWindow 实例代码,或者点击链接到github查看源代码,也可以在右侧发表评论。
private Editor createEditor(@Nonnull Document document, boolean isViewer, Project project, @Nonnull EditorKind kind) {
Document hostDocument = document instanceof DocumentWindow ? ((DocumentWindow)document).getDelegate() : document;
DesktopEditorImpl editor = new DesktopEditorImpl(hostDocument, isViewer, project, kind);
myEditors.add(editor);
myEditorEventMulticaster.registerEditor(editor);
EditorFactoryEvent event = new EditorFactoryEvent(this, editor);
myEditorFactoryEventDispatcher.getMulticaster().editorCreated(event);
EP.forEachExtensionSafe(it -> it.editorCreated(event));
if (LOG.isDebugEnabled()) {
LOG.debug("number of Editors after create: " + myEditors.size());
}
return editor;
}
@Override
@Nullable
public PsiFile getPsiFile(@Nonnull Document document) {
if (document instanceof DocumentWindow && !((DocumentWindow)document).isValid()) {
return null;
}
PsiFile psiFile = getCachedPsiFile(document);
if (psiFile != null) {
return ensureValidFile(psiFile, "Cached PSI");
}
final VirtualFile virtualFile = FileDocumentManager.getInstance().getFile(document);
if (virtualFile == null || !virtualFile.isValid()) return null;
psiFile = getPsiFile(virtualFile);
if (psiFile == null) return null;
fireFileCreated(document, psiFile);
return psiFile;
}
static OffsetsInFile toInjectedIfAny(PsiFile originalFile, OffsetsInFile hostCopyOffsets) {
CompletionAssertions.assertHostInfo(hostCopyOffsets.getFile(), hostCopyOffsets.getOffsets());
int hostStartOffset = hostCopyOffsets.getOffsets().getOffset(CompletionInitializationContext.START_OFFSET);
OffsetsInFile translatedOffsets = hostCopyOffsets.toInjectedIfAny(hostStartOffset);
if (translatedOffsets != hostCopyOffsets) {
PsiFile injected = translatedOffsets.getFile();
if (originalFile != injected && injected instanceof PsiFileImpl && InjectedLanguageManager.getInstance(originalFile.getProject()).isInjectedFragment(originalFile)) {
((PsiFileImpl)injected).setOriginalFile(originalFile);
}
DocumentWindow documentWindow = InjectedLanguageUtil.getDocumentWindow(injected);
CompletionAssertions.assertInjectedOffsets(hostStartOffset, injected, documentWindow);
if (injected.getTextRange().contains(translatedOffsets.getOffsets().getOffset(CompletionInitializationContext.START_OFFSET))) {
return translatedOffsets;
}
}
return hostCopyOffsets;
}
@Nonnull
public static Editor injectedEditorIfCharTypedIsSignificant(final int charTyped, @Nonnull Editor editor, @Nonnull PsiFile oldFile) {
int offset = editor.getCaretModel().getOffset();
// even for uncommitted document try to retrieve injected fragment that has been there recently
// we are assuming here that when user is (even furiously) typing, injected language would not change
// and thus we can use its lexer to insert closing braces etc
List<DocumentWindow> injected = InjectedLanguageManager.getInstance(oldFile.getProject()).getCachedInjectedDocumentsInRange(oldFile, ProperTextRange.create(offset, offset));
for (DocumentWindow documentWindow : injected) {
if (documentWindow.isValid() && documentWindow.containsRange(offset, offset)) {
PsiFile injectedFile = PsiDocumentManager.getInstance(oldFile.getProject()).getPsiFile(documentWindow);
if (injectedFile != null) {
Editor injectedEditor = InjectedLanguageUtil.getInjectedEditorForInjectedFile(editor, injectedFile);
// IDEA-52375/WEB-9105 fix: last quote in editable fragment should be handled by outer language quote handler
TextRange hostRange = documentWindow.getHostRange(offset);
CharSequence sequence = editor.getDocument().getCharsSequence();
if (sequence.length() > offset && charTyped != Character.codePointAt(sequence, offset) || hostRange != null && hostRange.contains(offset)) {
return injectedEditor;
}
}
}
}
return editor;
}
@Override
public void registerEmptyScope(@Nonnull Editor editor, int offset, int tabOutOffset) {
ApplicationManager.getApplication().assertIsDispatchThread();
if (editor.isDisposed()) throw new IllegalArgumentException("Editor is already disposed");
if (tabOutOffset <= offset) throw new IllegalArgumentException("tabOutOffset should be larger than offset");
if (!CodeInsightSettings.getInstance().TAB_EXITS_BRACKETS_AND_QUOTES) return;
if (editor instanceof EditorWindow) {
DocumentWindow documentWindow = ((EditorWindow)editor).getDocument();
offset = documentWindow.injectedToHost(offset);
editor = ((EditorWindow)editor).getDelegate();
}
if (!(editor instanceof DesktopEditorImpl)) return;
Tracker tracker = Tracker.forEditor((DesktopEditorImpl)editor, true);
tracker.registerScope(offset, tabOutOffset - offset);
}
private static int checkOrRemoveScopeEndingAt(@Nonnull Editor editor, int offset, boolean removeScope) {
ApplicationManager.getApplication().assertIsDispatchThread();
if (!CodeInsightSettings.getInstance().TAB_EXITS_BRACKETS_AND_QUOTES) return 0;
if (editor instanceof EditorWindow) {
DocumentWindow documentWindow = ((EditorWindow)editor).getDocument();
offset = documentWindow.injectedToHost(offset);
editor = ((EditorWindow)editor).getDelegate();
}
if (!(editor instanceof DesktopEditorImpl)) return 0;
Tracker tracker = Tracker.forEditor((DesktopEditorImpl)editor, false);
if (tracker == null) return 0;
return tracker.getCaretShiftForScopeEndingAt(offset, removeScope);
}
private static int insertLookupInDocumentWindowIfNeeded(Project project, Editor editor, int caretOffset, int prefix, String lookupString) {
DocumentWindow document = getInjectedDocument(project, editor, caretOffset);
if (document == null) return insertLookupInDocument(caretOffset, editor.getDocument(), prefix, lookupString);
PsiFile file = PsiDocumentManager.getInstance(project).getPsiFile(document);
int offset = document.hostToInjected(caretOffset);
int lookupStart = Math.min(offset, Math.max(offset - prefix, 0));
int diff = -1;
if (file != null) {
List<TextRange> ranges = InjectedLanguageManager.getInstance(project).intersectWithAllEditableFragments(file, TextRange.create(lookupStart, offset));
if (!ranges.isEmpty()) {
diff = ranges.get(0).getStartOffset() - lookupStart;
if (ranges.size() == 1 && diff == 0) diff = -1;
}
}
if (diff == -1) return insertLookupInDocument(caretOffset, editor.getDocument(), prefix, lookupString);
return document.injectedToHost(insertLookupInDocument(offset, document, prefix - diff, diff == 0 ? lookupString : lookupString.substring(diff)));
}
@Override
public boolean areRangesEqual(@Nonnull DocumentWindow other) {
DocumentWindowImpl window = (DocumentWindowImpl)other;
Place shreds = getShreds();
Place otherShreds = window.getShreds();
if (shreds.size() != otherShreds.size()) return false;
for (int i = 0; i < shreds.size(); i++) {
PsiLanguageInjectionHost.Shred shred = shreds.get(i);
PsiLanguageInjectionHost.Shred otherShred = otherShreds.get(i);
if (!shred.getPrefix().equals(otherShred.getPrefix())) return false;
if (!shred.getSuffix().equals(otherShred.getSuffix())) return false;
Segment hostRange = shred.getHostRangeMarker();
Segment otherRange = otherShred.getHostRangeMarker();
if (hostRange == null || otherRange == null || !TextRange.areSegmentsEqual(hostRange, otherRange)) return false;
}
return true;
}
@Nonnull
@Override
public List<TextRange> getNonEditableFragments(@Nonnull DocumentWindow window) {
List<TextRange> result = new ArrayList<>();
int offset = 0;
for (PsiLanguageInjectionHost.Shred shred : ((DocumentWindowImpl)window).getShreds()) {
Segment hostRange = shred.getHostRangeMarker();
if (hostRange == null) continue;
offset = appendRange(result, offset, shred.getPrefix().length());
offset += hostRange.getEndOffset() - hostRange.getStartOffset();
offset = appendRange(result, offset, shred.getSuffix().length());
}
return result;
}
static void clearCaches(@Nonnull PsiFile injected, @Nonnull DocumentWindowImpl documentWindow) {
VirtualFileWindowImpl virtualFile = (VirtualFileWindowImpl)injected.getVirtualFile();
PsiManagerEx psiManagerEx = (PsiManagerEx)injected.getManager();
if (psiManagerEx.getProject().isDisposed()) return;
DebugUtil.performPsiModification("injected clearCaches", () -> psiManagerEx.getFileManager().setViewProvider(virtualFile, null));
VirtualFile delegate = virtualFile.getDelegate();
if (!delegate.isValid()) return;
FileViewProvider viewProvider = psiManagerEx.getFileManager().findCachedViewProvider(delegate);
if (viewProvider == null) return;
for (PsiFile hostFile : ((AbstractFileViewProvider)viewProvider).getCachedPsiFiles()) {
// modification of cachedInjectedDocuments must be under InjectedLanguageManagerImpl.ourInjectionPsiLock
synchronized (InjectedLanguageManagerImpl.ourInjectionPsiLock) {
List<DocumentWindow> cachedInjectedDocuments = getCachedInjectedDocuments(hostFile);
for (int i = cachedInjectedDocuments.size() - 1; i >= 0; i--) {
DocumentWindow cachedInjectedDocument = cachedInjectedDocuments.get(i);
if (cachedInjectedDocument == documentWindow) {
cachedInjectedDocuments.remove(i);
}
}
}
}
}
public static BooleanRunnable reparse(@Nonnull PsiFile injectedPsiFile,
@Nonnull DocumentWindow injectedDocument,
@Nonnull PsiFile hostPsiFile,
@Nonnull Document hostDocument,
@Nonnull FileViewProvider hostViewProvider,
@Nonnull ProgressIndicator indicator,
@Nonnull ASTNode oldRoot,
@Nonnull ASTNode newRoot,
@Nonnull PsiDocumentManagerBase documentManager) {
LanguageVersion languageVersion = injectedPsiFile.getLanguageVersion();
InjectedFileViewProvider provider = (InjectedFileViewProvider)injectedPsiFile.getViewProvider();
VirtualFile oldInjectedVFile = provider.getVirtualFile();
VirtualFile hostVirtualFile = hostViewProvider.getVirtualFile();
BooleanRunnable runnable = InjectionRegistrarImpl
.reparse(languageVersion, (DocumentWindowImpl)injectedDocument, injectedPsiFile, (VirtualFileWindow)oldInjectedVFile, hostVirtualFile, hostPsiFile, (DocumentEx)hostDocument, indicator, oldRoot,
newRoot, documentManager);
if (runnable == null) {
EditorWindowImpl.disposeEditorFor(injectedDocument);
}
return runnable;
}
public static TodoItem[] findAllTodos(final PsiFile psiFile, final PsiTodoSearchHelper helper) {
final List<TodoItem> todoItems = new ArrayList<>(Arrays.asList(helper.findTodoItems(psiFile)));
psiFile.accept(new PsiRecursiveElementWalkingVisitor() {
@Override
public void visitElement(PsiElement element) {
if (element instanceof PsiLanguageInjectionHost) {
InjectedLanguageManager.getInstance(psiFile.getProject()).enumerate(element, (injectedPsi, places) -> {
if (places.size() == 1) {
Document document = PsiDocumentManager.getInstance(injectedPsi.getProject()).getCachedDocument(injectedPsi);
if (!(document instanceof DocumentWindow)) return;
for (TodoItem item : helper.findTodoItems(injectedPsi)) {
TextRange rangeInHost = ((DocumentWindow)document).injectedToHost(item.getTextRange());
List<TextRange> additionalRanges = ContainerUtil.map(item.getAdditionalTextRanges(), ((DocumentWindow)document)::injectedToHost);
TodoItemImpl hostItem = new TodoItemImpl(psiFile, rangeInHost.getStartOffset(), rangeInHost.getEndOffset(), item.getPattern(), additionalRanges);
todoItems.add(hostItem);
}
}
});
}
super.visitElement(element);
}
});
return todoItems.toArray(new TodoItem[0]);
}
@NotNull
private List<Block> buildInjectedBlocks() {
PsiElement psi = myNode.getPsi();
if (psi == null) {
return EMPTY;
}
PsiFile file = psi.getContainingFile();
if (file == null) {
return EMPTY;
}
if (InjectedLanguageUtil.getCachedInjectedDocuments(file).isEmpty()) {
return EMPTY;
}
TextRange blockRange = myNode.getTextRange();
List<DocumentWindow> documentWindows = InjectedLanguageUtil.getCachedInjectedDocuments(file);
for (DocumentWindow documentWindow : documentWindows) {
int startOffset = documentWindow.injectedToHost(0);
int endOffset = startOffset + documentWindow.getTextLength();
if (blockRange.containsRange(startOffset, endOffset)) {
PsiFile injected = PsiDocumentManager.getInstance(psi.getProject()).getCachedPsiFile(documentWindow);
if (injected != null) {
List<Block> result = ContainerUtilRt.newArrayList();
GraphQLInjectedLanguageBlockBuilder builder = new GraphQLInjectedLanguageBlockBuilder(settings);
builder.addInjectedBlocks(result, myNode, getWrap(), getAlignment(), getIndent());
return result;
}
}
}
return EMPTY;
}
protected void bringRealEditorBack() {
PsiDocumentManager.getInstance(getProject()).commitAllDocuments();
if (myEditor instanceof EditorWindow) {
Document document = ((DocumentWindow)myEditor.getDocument()).getDelegate();
myFile = PsiDocumentManager.getInstance(getProject()).getPsiFile(document);
myEditor = ((EditorWindow)myEditor).getDelegate();
}
}
protected static void bringRealEditorBack() {
PsiDocumentManager.getInstance(getProject()).commitAllDocuments();
if (myEditor instanceof EditorWindow) {
Document document = ((DocumentWindow)myEditor.getDocument()).getDelegate();
myFile = PsiDocumentManager.getInstance(getProject()).getPsiFile(document);
myEditor = ((EditorWindow)myEditor).getDelegate();
myVFile = myFile.getVirtualFile();
}
}
public void clearLineModificationFlags(@Nonnull Document document) {
if (document instanceof DocumentWindow) {
document = ((DocumentWindow)document).getDelegate();
}
if (!(document instanceof DocumentImpl)) {
return;
}
Editor activeEditor = getActiveEditor(document);
// when virtual space enabled, we can strip whitespace anywhere
boolean isVirtualSpaceEnabled = activeEditor == null || activeEditor.getSettings().isVirtualSpace();
final EditorSettingsExternalizable settings = EditorSettingsExternalizable.getInstance();
if (settings == null) return;
boolean enabled = !Boolean.TRUE.equals(DISABLE_FOR_FILE_KEY.get(FileDocumentManager.getInstance().getFile(document)));
if (!enabled) return;
String stripTrailingSpaces = settings.getStripTrailingSpaces();
final boolean doStrip = !stripTrailingSpaces.equals(EditorSettingsExternalizable.STRIP_TRAILING_SPACES_NONE);
final boolean inChangedLinesOnly = !stripTrailingSpaces.equals(EditorSettingsExternalizable.STRIP_TRAILING_SPACES_WHOLE);
int[] caretLines;
if (activeEditor != null && inChangedLinesOnly && doStrip && !isVirtualSpaceEnabled) {
List<Caret> carets = activeEditor.getCaretModel().getAllCarets();
caretLines = new int[carets.size()];
for (int i = 0; i < carets.size(); i++) {
Caret caret = carets.get(i);
caretLines[i] = caret.getLogicalPosition().line;
}
}
else {
caretLines = ArrayUtil.EMPTY_INT_ARRAY;
}
((DocumentImpl)document).clearLineModificationFlagsExcept(caretLines);
}
@Override
public ReadonlyFragmentModificationHandler getReadonlyFragmentModificationHandler(@Nonnull final Document document) {
final Document doc = document instanceof DocumentWindow ? ((DocumentWindow)document).getDelegate() : document;
final ReadonlyFragmentModificationHandler docHandler =
doc instanceof DocumentImpl ? ((DocumentImpl)doc).getReadonlyFragmentModificationHandler() : null;
return docHandler == null ? myReadonlyFragmentsHandler : docHandler;
}
@Override
public void setReadonlyFragmentModificationHandler(@Nonnull final Document document, final ReadonlyFragmentModificationHandler handler) {
final Document doc = document instanceof DocumentWindow ? ((DocumentWindow)document).getDelegate() : document;
if (doc instanceof DocumentImpl) {
((DocumentImpl)document).setReadonlyFragmentModificationHandler(handler);
}
}
public static <T extends PsiElement> T getOriginalElement(@Nonnull T psi, PsiFile containingFile) {
if (containingFile != null && containingFile != containingFile.getOriginalFile() && psi.getTextRange() != null) {
TextRange range = psi.getTextRange();
Integer start = range.getStartOffset();
Integer end = range.getEndOffset();
final Document document = containingFile.getViewProvider().getDocument();
if (document != null) {
Document hostDocument = document instanceof DocumentWindow ? ((DocumentWindow)document).getDelegate() : document;
OffsetTranslator translator = hostDocument.getUserData(OffsetTranslator.RANGE_TRANSLATION);
if (translator != null) {
if (document instanceof DocumentWindow) {
TextRange translated = ((DocumentWindow)document).injectedToHost(new TextRange(start, end));
start = translated.getStartOffset();
end = translated.getEndOffset();
}
start = translator.translateOffset(start);
end = translator.translateOffset(end);
if (start == null || end == null) {
return null;
}
if (document instanceof DocumentWindow) {
start = ((DocumentWindow)document).hostToInjected(start);
end = ((DocumentWindow)document).hostToInjected(end);
}
}
}
//noinspection unchecked
return (T)PsiTreeUtil.findElementOfClassAtRange(containingFile.getOriginalFile(), start, end, psi.getClass());
}
return psi;
}
private void checkLengthConsistency() {
Document document = getCachedDocument();
if (document instanceof DocumentWindow) {
return;
}
if (document != null && ((PsiDocumentManagerBase)PsiDocumentManager.getInstance(myManager.getProject())).getSynchronizer().isInSynchronization(document)) {
return;
}
List<FileElement> knownTreeRoots = getKnownTreeRoots();
if (knownTreeRoots.isEmpty()) return;
int fileLength = myContent.getTextLength();
for (FileElement fileElement : knownTreeRoots) {
int nodeLength = fileElement.getTextLength();
if (!isDocumentConsistentWithPsi(fileLength, fileElement, nodeLength)) {
PsiUtilCore.ensureValid(fileElement.getPsi());
List<Attachment> attachments = ContainerUtil
.newArrayList(new Attachment(myVirtualFile.getName(), myContent.getText().toString()), new Attachment(myVirtualFile.getNameWithoutExtension() + ".tree.txt", fileElement.getText()));
if (document != null) {
attachments.add(new Attachment(myVirtualFile.getNameWithoutExtension() + ".document.txt", document.getText()));
}
// exceptions here should be assigned to peter
LOG.error("Inconsistent " + fileElement.getElementType() + " tree in " + this + "; nodeLength=" + nodeLength + "; fileLength=" + fileLength, attachments.toArray(Attachment.EMPTY_ARRAY));
}
}
}
private DocumentEx getCachedDocument(PsiFile psiFile, boolean force) {
final DocumentEx document = (DocumentEx)myPsiDocumentManager.getCachedDocument(psiFile);
if (document == null || document instanceof DocumentWindow || !force && getTransaction(document) == null) {
return null;
}
return document;
}
static void assertInjectedOffsets(int hostStartOffset, PsiFile injected, DocumentWindow documentWindow) {
assert documentWindow != null : "no DocumentWindow for an injected fragment";
InjectedLanguageManager injectedLanguageManager = InjectedLanguageManager.getInstance(injected.getProject());
TextRange injectedRange = injected.getTextRange();
int hostMinOffset = injectedLanguageManager.injectedToHost(injected, injectedRange.getStartOffset(), true);
int hostMaxOffset = injectedLanguageManager.injectedToHost(injected, injectedRange.getEndOffset(), false);
assert hostStartOffset >= hostMinOffset : "startOffset before injected";
assert hostStartOffset <= hostMaxOffset : "startOffset after injected";
}
void duringCompletion(CompletionInitializationContext initContext, CompletionParameters parameters) {
if (isAutopopupCompletion() && shouldPreselectFirstSuggestion(parameters)) {
myLookup.setFocusDegree(CodeInsightSettings.getInstance().isSelectAutopopupSuggestionsByChars() ? LookupImpl.FocusDegree.FOCUSED : LookupImpl.FocusDegree.SEMI_FOCUSED);
}
addDefaultAdvertisements(parameters);
ProgressManager.checkCanceled();
Document document = initContext.getEditor().getDocument();
if (!initContext.getOffsetMap().wasModified(CompletionInitializationContext.IDENTIFIER_END_OFFSET)) {
try {
final int selectionEndOffset = initContext.getSelectionEndOffset();
final PsiReference reference = TargetElementUtil.findReference(myEditor, selectionEndOffset);
if (reference != null) {
final int replacementOffset = findReplacementOffset(selectionEndOffset, reference);
if (replacementOffset > document.getTextLength()) {
LOG.error("Invalid replacementOffset: " + replacementOffset + " returned by reference " + reference + " of " + reference.getClass() +
"; doc=" + document +
"; doc actual=" + (document == initContext.getFile().getViewProvider().getDocument()) +
"; doc committed=" + PsiDocumentManager.getInstance(getProject()).isCommitted(document));
}
else {
initContext.setReplacementOffset(replacementOffset);
}
}
}
catch (IndexNotReadyException ignored) {
}
}
for (CompletionContributor contributor : CompletionContributor.forLanguageHonorDumbness(initContext.getPositionLanguage(), initContext.getProject())) {
ProgressManager.checkCanceled();
contributor.duringCompletion(initContext);
}
if (document instanceof DocumentWindow) {
myHostOffsets = new OffsetsInFile(initContext.getFile(), initContext.getOffsetMap()).toTopLevelFile();
}
}
private static void queryLineMarkersForInjected(@Nonnull PsiElement element,
@Nonnull final PsiFile containingFile,
@Nonnull Set<? super PsiFile> visitedInjectedFiles,
@Nonnull final PairConsumer<? super PsiElement, ? super LineMarkerInfo<PsiElement>> consumer) {
final InjectedLanguageManager manager = InjectedLanguageManager.getInstance(containingFile.getProject());
if (manager.isInjectedFragment(containingFile)) return;
InjectedLanguageManager.getInstance(containingFile.getProject()).enumerateEx(element, containingFile, false, (injectedPsi, places) -> {
if (!visitedInjectedFiles.add(injectedPsi)) return; // there may be several concatenated literals making the one injected file
final Project project = injectedPsi.getProject();
Document document = PsiDocumentManager.getInstance(project).getCachedDocument(injectedPsi);
if (!(document instanceof DocumentWindow)) return;
List<PsiElement> injElements = CollectHighlightsUtil.getElementsInRange(injectedPsi, 0, injectedPsi.getTextLength());
final List<LineMarkerProvider> providers = getMarkerProviders(injectedPsi.getLanguage(), project);
queryProviders(injElements, injectedPsi, providers, (injectedElement, injectedMarker) -> {
GutterIconRenderer gutterRenderer = injectedMarker.createGutterRenderer();
TextRange injectedRange = new TextRange(injectedMarker.startOffset, injectedMarker.endOffset);
List<TextRange> editables = manager.intersectWithAllEditableFragments(injectedPsi, injectedRange);
for (TextRange editable : editables) {
TextRange hostRange = manager.injectedToHost(injectedPsi, editable);
Image icon = gutterRenderer == null ? null : gutterRenderer.getIcon();
GutterIconNavigationHandler<PsiElement> navigationHandler = injectedMarker.getNavigationHandler();
LineMarkerInfo<PsiElement> converted =
new LineMarkerInfo<>(injectedElement, hostRange, icon, injectedMarker.updatePass, e -> injectedMarker.getLineMarkerTooltip(), navigationHandler, GutterIconRenderer.Alignment.RIGHT);
consumer.consume(injectedElement, converted);
}
});
});
}
private void addDescriptorsFromInjectedResults(@Nonnull InspectionManager iManager, @Nonnull GlobalInspectionContextImpl context) {
InjectedLanguageManager ilManager = InjectedLanguageManager.getInstance(myProject);
PsiDocumentManager documentManager = PsiDocumentManager.getInstance(myProject);
for (Map.Entry<PsiFile, List<InspectionResult>> entry : result.entrySet()) {
PsiFile file = entry.getKey();
if (file == getFile()) continue; // not injected
DocumentWindow documentRange = (DocumentWindow)documentManager.getDocument(file);
List<InspectionResult> resultList = entry.getValue();
for (InspectionResult inspectionResult : resultList) {
LocalInspectionToolWrapper toolWrapper = inspectionResult.tool;
for (ProblemDescriptor descriptor : inspectionResult.foundProblems) {
PsiElement psiElement = descriptor.getPsiElement();
if (psiElement == null) continue;
if (SuppressionUtil.inspectionResultSuppressed(psiElement, toolWrapper.getTool())) continue;
List<TextRange> editables = ilManager.intersectWithAllEditableFragments(file, ((ProblemDescriptorBase)descriptor).getTextRange());
for (TextRange editable : editables) {
TextRange hostRange = documentRange.injectedToHost(editable);
QuickFix[] fixes = descriptor.getFixes();
LocalQuickFix[] localFixes = null;
if (fixes != null) {
localFixes = new LocalQuickFix[fixes.length];
for (int k = 0; k < fixes.length; k++) {
QuickFix fix = fixes[k];
localFixes[k] = (LocalQuickFix)fix;
}
}
ProblemDescriptor patchedDescriptor =
iManager.createProblemDescriptor(getFile(), hostRange, descriptor.getDescriptionTemplate(), descriptor.getHighlightType(), true,
localFixes);
addDescriptors(toolWrapper, patchedDescriptor, context);
}
}
}
}
}
/**
* finds the first nearest text range
* @param documentWindow
* @param startOffset
* @return null means invalid
*/
@Nullable
private static TextRange findNearestTextRange(final DocumentWindow documentWindow, final int startOffset) {
TextRange textRange = null;
for (Segment marker : documentWindow.getHostRanges()) {
TextRange curRange = ProperTextRange.create(marker);
if (curRange.getStartOffset() > startOffset && textRange != null) break;
textRange = curRange;
}
return textRange;
}
@Nullable
private static DocumentWindow getInjectedDocument(Project project, Editor editor, int offset) {
PsiFile hostFile = PsiDocumentManager.getInstance(project).getPsiFile(editor.getDocument());
if (hostFile != null) {
// inspired by com.intellij.codeInsight.editorActions.TypedHandler.injectedEditorIfCharTypedIsSignificant()
List<DocumentWindow> injected = InjectedLanguageManager.getInstance(project).getCachedInjectedDocumentsInRange(hostFile, TextRange.create(offset, offset));
for (DocumentWindow documentWindow : injected) {
if (documentWindow.isValid() && documentWindow.containsRange(offset, offset)) {
return documentWindow;
}
}
}
return null;
}
@Override
@Nonnull
public Editor getEditor() {
DocumentWindow documentWindow = getInjectedDocument(myProject, myEditor, myEditor.getCaretModel().getOffset());
if (documentWindow != null) {
PsiFile injectedFile = PsiDocumentManager.getInstance(myProject).getPsiFile(documentWindow);
return InjectedLanguageUtil.getInjectedEditorForInjectedFile(myEditor, injectedFile);
}
return myEditor;
}
public QuickEditHandler invokeImpl(@Nonnull final Project project, final Editor editor, PsiFile file) throws IncorrectOperationException {
int offset = editor.getCaretModel().getOffset();
Pair<PsiElement, TextRange> pair = ObjectUtils.assertNotNull(getRangePair(file, editor));
PsiFile injectedFile = (PsiFile)pair.first;
QuickEditHandler handler = getHandler(project, injectedFile, editor, file);
if (!ApplicationManager.getApplication().isUnitTestMode()) {
DocumentWindow documentWindow = InjectedLanguageUtil.getDocumentWindow(injectedFile);
if (documentWindow != null) {
handler.navigate(InjectedLanguageUtil.hostToInjectedUnescaped(documentWindow, offset));
}
}
return handler;
}
public static QuickEditHandler getExistingHandler(@Nonnull PsiFile injectedFile) {
Place shreds = InjectedLanguageUtil.getShreds(injectedFile);
DocumentWindow documentWindow = InjectedLanguageUtil.getDocumentWindow(injectedFile);
if (shreds == null || documentWindow == null) return null;
TextRange hostRange = TextRange.create(shreds.get(0).getHostRangeMarker().getStartOffset(),
shreds.get(shreds.size() - 1).getHostRangeMarker().getEndOffset());
for (Editor editor : EditorFactory.getInstance().getAllEditors()) {
if (editor.getDocument() != documentWindow.getDelegate()) continue;
QuickEditHandler handler = editor.getUserData(QUICK_EDIT_HANDLER);
if (handler != null && handler.changesRange(hostRange)) return handler;
}
return null;
}