void (@NotNull HighlightInfo info, @NotNull PsiFile injectedPsi, @NotNull DocumentWindow documentWindow, @NotNull InjectedLanguageManager injectedLanguageManager, @NotNull Consumer<? super HighlightInfo> outInfos) { ProperTextRange infoRange = new ProperTextRange(info.startOffset, info.endOffset); List<TextRange> editables = injectedLanguageManager.intersectWithAllEditableFragments(injectedPsi, infoRange); for (TextRange editable : editables) { TextRange hostRange = documentWindow.injectedToHost(editable); boolean isAfterEndOfLine = info.isAfterEndOfLine(); if (isAfterEndOfLine) { // convert injected afterEndOfLine to either host's afterEndOfLine or not-afterEndOfLine highlight of the injected fragment boundary int hostEndOffset = hostRange.getEndOffset(); int lineNumber = documentWindow.getDelegate().getLineNumber(hostEndOffset); int hostLineEndOffset = documentWindow.getDelegate().getLineEndOffset(lineNumber); if (hostEndOffset < hostLineEndOffset) { // convert to non-afterEndOfLine isAfterEndOfLine = false; hostRange = new ProperTextRange(hostRange.getStartOffset(), hostEndOffset+1); } } HighlightInfo patched = new HighlightInfo(info.forcedTextAttributes, info.forcedTextAttributesKey, info.type, hostRange.getStartOffset(), hostRange.getEndOffset(), info.getDescription(), info.getToolTip(), info.getSeverity(), isAfterEndOfLine, null, false, 0, info.getProblemGroup(), info.toolId, info.getGutterIconRenderer(), info.getGroup(), info.unresolvedReference); patched.setHint(info.hasHint()); info.findRegisteredQuickFix((descriptor, quickfixTextRange) -> { List<TextRange> editableQF = injectedLanguageManager.intersectWithAllEditableFragments(injectedPsi, quickfixTextRange); for (TextRange editableRange : editableQF) { TextRange hostEditableRange = documentWindow.injectedToHost(editableRange); patched.registerFix(descriptor.getAction(), descriptor.myOptions, descriptor.getDisplayName(), hostEditableRange, descriptor.myKey); } return null; }); patched.markFromInjection(); outInfos.accept(patched); } }