private static void highlightTodos( @NotNull PsiFile file, @NotNull CharSequence text, int startOffset, int endOffset, @NotNull ProgressIndicator progress, @NotNull ProperTextRange priorityRange, @NotNull Collection<HighlightInfo> result, @NotNull Collection<HighlightInfo> outsideResult) { PsiSearchHelper helper = PsiSearchHelper.SERVICE.getInstance(file.getProject()); TodoItem[] todoItems = helper.findTodoItems(file, startOffset, endOffset); if (todoItems.length == 0) return; for (TodoItem todoItem : todoItems) { progress.checkCanceled(); TextRange range = todoItem.getTextRange(); String description = text.subSequence(range.getStartOffset(), range.getEndOffset()).toString(); TextAttributes attributes = todoItem.getPattern().getAttributes().getTextAttributes(); HighlightInfo info = HighlightInfo.createHighlightInfo( HighlightInfoType.TODO, range, description, description, attributes); assert info != null; if (priorityRange.containsRange(info.getStartOffset(), info.getEndOffset())) { result.add(info); } else { outsideResult.add(info); } } }
public synchronized boolean addRoots( @NotNull String name, Module moduleContext, @NotNull Object elements) { Collection<AbstractTreeNode> nodes = AddToFavoritesAction.createNodes( myProject, moduleContext, elements, true, getViewSettings()); return !nodes.isEmpty() && addRoots(name, nodes); }
public void setHighlightingEnabled(@NotNull PsiFile file, boolean value) { if (value) { myDisabledHighlightingFiles.remove(file); } else { myDisabledHighlightingFiles.add(file); } }
public List<ShelvedChangeList> importChangeLists( final Collection<VirtualFile> files, final Consumer<VcsException> exceptionConsumer) { final List<ShelvedChangeList> result = new ArrayList<ShelvedChangeList>(files.size()); try { final FilesProgress filesProgress = new FilesProgress(files.size(), "Processing "); for (VirtualFile file : files) { filesProgress.updateIndicator(file); final String description = file.getNameWithoutExtension().replace('_', ' '); final File patchPath = getPatchPath(description); final ShelvedChangeList list = new ShelvedChangeList( patchPath.getPath(), description, new SmartList<ShelvedBinaryFile>(), file.getTimeStamp()); try { final List<TextFilePatch> patchesList = loadPatches(myProject, file.getPath(), new CommitContext()); if (!patchesList.isEmpty()) { FileUtil.copy(new File(file.getPath()), patchPath); // add only if ok to read patch myShelvedChangeLists.add(list); result.add(list); } } catch (IOException e) { exceptionConsumer.consume(new VcsException(e)); } catch (PatchSyntaxException e) { exceptionConsumer.consume(new VcsException(e)); } } } finally { notifyStateChanged(); } return result; }
private void doPostponedFormattingInner(final FileViewProvider key) { final List<ASTNode> astNodes = myReformatElements.remove(key); final Document document = key.getDocument(); // Sort ranges by end offsets so that we won't need any offset adjustment after reformat or // reindent if (document == null) return; final VirtualFile virtualFile = key.getVirtualFile(); if (!virtualFile.isValid()) return; final TreeSet<PostprocessFormattingTask> postProcessTasks = new TreeSet<PostprocessFormattingTask>(); Collection<Disposable> toDispose = ContainerUtilRt.newArrayList(); try { // process all roots in viewProvider to find marked for reformat before elements and create // appropriate range markers handleReformatMarkers(key, postProcessTasks); toDispose.addAll(postProcessTasks); // then we create ranges by changed nodes. One per node. There ranges can intersect. Ranges // are sorted by end offset. if (astNodes != null) createActionsMap(astNodes, key, postProcessTasks); if ("true".equals(System.getProperty("check.psi.is.valid")) && ApplicationManager.getApplication().isUnitTestMode()) { checkPsiIsCorrect(key); } while (!postProcessTasks.isEmpty()) { // now we have to normalize actions so that they not intersect and ordered in most // appropriate way // (free reformatting -> reindent -> formatting under reindent) final List<PostponedAction> normalizedActions = normalizeAndReorderPostponedActions(postProcessTasks, document); toDispose.addAll(normalizedActions); // only in following loop real changes in document are made for (final PostponedAction normalizedAction : normalizedActions) { CodeStyleSettings settings = CodeStyleSettingsManager.getSettings(myPsiManager.getProject()); boolean old = settings.ENABLE_JAVADOC_FORMATTING; settings.ENABLE_JAVADOC_FORMATTING = false; try { normalizedAction.execute(key); } finally { settings.ENABLE_JAVADOC_FORMATTING = old; } } } } finally { for (Disposable disposable : toDispose) { //noinspection SSBasedInspection disposable.dispose(); } } }
@Override public void setHighlightingEnabled(@NotNull PsiFile file, boolean value) { VirtualFile virtualFile = PsiUtilCore.getVirtualFile(file); if (value) { myDisabledHighlightingFiles.remove(virtualFile); } else { myDisabledHighlightingFiles.add(virtualFile); } }
public static <T> void assertSameElements( String message, Collection<? extends T> collection, Collection<T> expected) { assertNotNull(collection); assertNotNull(expected); if (collection.size() != expected.size() || !new HashSet<T>(expected).equals(new HashSet<T>(collection))) { Assert.assertEquals(message, toString(expected, "\n"), toString(collection, "\n")); Assert.assertEquals(message, new HashSet<T>(expected), new HashSet<T>(collection)); } }
public void setImportHintsEnabled(@NotNull PsiFile file, boolean value) { VirtualFile vFile = file.getVirtualFile(); if (value) { myDisabledHintsFiles.remove(vFile); stopProcess(true); } else { myDisabledHintsFiles.add(vFile); HintManager.getInstance().hideAllHints(); } }
private void getInjectedPsiFiles( @NotNull final List<PsiElement> elements1, @NotNull final List<PsiElement> elements2, @NotNull final ProgressIndicator progress, @NotNull final Set<PsiFile> outInjected) { List<DocumentWindow> injected = InjectedLanguageUtil.getCachedInjectedDocuments(myFile); Collection<PsiElement> hosts = new THashSet<PsiElement>(elements1.size() + elements2.size() + injected.size()); // rehighlight all injected PSI regardless the range, // since change in one place can lead to invalidation of injected PSI in (completely) other // place. for (DocumentWindow documentRange : injected) { progress.checkCanceled(); if (!documentRange.isValid()) continue; PsiFile file = PsiDocumentManager.getInstance(myProject).getPsiFile(documentRange); if (file == null) continue; PsiElement context = InjectedLanguageManager.getInstance(file.getProject()).getInjectionHost(file); if (context != null && context.isValid() && !file.getProject().isDisposed() && (myUpdateAll || new ProperTextRange(myStartOffset, myEndOffset) .intersects(context.getTextRange()))) { hosts.add(context); } } hosts.addAll(elements1); hosts.addAll(elements2); final PsiLanguageInjectionHost.InjectedPsiVisitor visitor = new PsiLanguageInjectionHost.InjectedPsiVisitor() { @Override public void visit( @NotNull PsiFile injectedPsi, @NotNull List<PsiLanguageInjectionHost.Shred> places) { synchronized (outInjected) { outInjected.add(injectedPsi); } } }; if (!JobUtil.invokeConcurrentlyUnderProgress( new ArrayList<PsiElement>(hosts), progress, false, new Processor<PsiElement>() { @Override public boolean process(PsiElement element) { progress.checkCanceled(); InjectedLanguageUtil.enumerate(element, myFile, false, visitor); return true; } })) throw new ProcessCanceledException(); }
public static <T> void assertUnorderedCollection( Collection<? extends T> collection, Consumer<T>... checkers) { Assert.assertNotNull(collection); if (collection.size() != checkers.length) { Assert.fail(toString(collection)); } Set<Consumer<T>> checkerSet = new HashSet<Consumer<T>>(Arrays.asList(checkers)); int i = 0; Throwable lastError = null; for (final T actual : collection) { boolean flag = true; for (final Consumer<T> condition : checkerSet) { Throwable error = accepts(condition, actual); if (error == null) { checkerSet.remove(condition); flag = false; break; } else { lastError = error; } } if (flag) { lastError.printStackTrace(); Assert.fail("Incorrect element(" + i + "): " + actual); } i++; } }
public void checkLineMarkers( @NotNull Collection<LineMarkerInfo> markerInfos, @NotNull String text) { String fileName = myFile == null ? "" : myFile.getName() + ": "; String failMessage = ""; for (LineMarkerInfo info : markerInfos) { if (!containsLineMarker(info, myLineMarkerInfos.values())) { if (!failMessage.isEmpty()) failMessage += '\n'; failMessage += fileName + "Extra line marker highlighted " + rangeString(text, info.startOffset, info.endOffset) + ": '" + info.getLineMarkerTooltip() + "'"; } } for (LineMarkerInfo expectedLineMarker : myLineMarkerInfos.values()) { if (!markerInfos.isEmpty() && !containsLineMarker(expectedLineMarker, markerInfos)) { if (!failMessage.isEmpty()) failMessage += '\n'; failMessage += fileName + "Line marker was not highlighted " + rangeString(text, expectedLineMarker.startOffset, expectedLineMarker.endOffset) + ": '" + expectedLineMarker.getLineMarkerTooltip() + "'"; } } if (!failMessage.isEmpty()) Assert.fail(failMessage); }
public void readExternal(Element parentNode) throws InvalidDataException { myDisabledHintsFiles.clear(); Element element = parentNode.getChild(DISABLE_HINTS_TAG); if (element != null) { for (Object o : element.getChildren(FILE_TAG)) { Element e = (Element) o; String url = e.getAttributeValue(URL_ATT); if (url != null) { VirtualFile file = VirtualFileManager.getInstance().findFileByUrl(url); if (file != null) { myDisabledHintsFiles.add(file); } } } } }
private void addAllPointers(@NotNull Collection<VirtualFilePointerImpl> pointers) { List<FilePointerPartNode> out = new ArrayList<FilePointerPartNode>(); for (FilePointerPartNode root : myPointers.values()) { root.getPointersUnder(null, false, "", out); } for (FilePointerPartNode node : out) { pointers.add(node.leaf); } }
static void importInjections( final Collection<BaseInjection> existingInjections, final Collection<BaseInjection> importingInjections, final Collection<BaseInjection> originalInjections, final Collection<BaseInjection> newInjections) { final MultiValuesMap<InjectionPlace, BaseInjection> placeMap = new MultiValuesMap<InjectionPlace, BaseInjection>(); for (BaseInjection exising : existingInjections) { for (InjectionPlace place : exising.getInjectionPlaces()) { placeMap.put(place, exising); } } main: for (BaseInjection other : importingInjections) { final List<BaseInjection> matchingInjections = ContainerUtil.concat( other.getInjectionPlaces(), new Function<InjectionPlace, Collection<? extends BaseInjection>>() { public Collection<? extends BaseInjection> fun(final InjectionPlace o) { final Collection<BaseInjection> collection = placeMap.get(o); return collection == null ? Collections.<BaseInjection>emptyList() : collection; } }); if (matchingInjections.isEmpty()) { newInjections.add(other); } else { BaseInjection existing = null; for (BaseInjection injection : matchingInjections) { if (injection.equals(other)) continue main; if (existing == null && injection.sameLanguageParameters(other)) { existing = injection; } } if (existing == null) continue main; // skip!! language changed final BaseInjection newInjection = existing.copy(); newInjection.mergeOriginalPlacesFrom(other, true); if (!newInjection.equals(existing)) { originalInjections.add(existing); newInjections.add(newInjection); } } } }
static void loadDescriptorsFromClassPath( @NotNull List<IdeaPluginDescriptorImpl> result, @Nullable StartupProgress progress) { Collection<URL> urls = getClassLoaderUrls(); String platformPrefix = System.getProperty(PlatformUtilsCore.PLATFORM_PREFIX_KEY); int i = 0; for (URL url : urls) { i++; if ("file".equals(url.getProtocol())) { File file = new File(decodeUrl(url.getFile())); IdeaPluginDescriptorImpl platformPluginDescriptor = null; if (platformPrefix != null) { platformPluginDescriptor = loadDescriptor(file, platformPrefix + "Plugin.xml"); if (platformPluginDescriptor != null && !result.contains(platformPluginDescriptor)) { platformPluginDescriptor.setUseCoreClassLoader(true); result.add(platformPluginDescriptor); } } IdeaPluginDescriptorImpl pluginDescriptor = loadDescriptor(file, PLUGIN_XML); if (platformPrefix != null && pluginDescriptor != null && pluginDescriptor.getName().equals(SPECIAL_IDEA_PLUGIN)) { continue; } if (pluginDescriptor != null && !result.contains(pluginDescriptor)) { if (platformPluginDescriptor != null) { // if we found a regular plugin.xml in the same .jar/root as a platform-prefixed // descriptor, use the core loader for it too pluginDescriptor.setUseCoreClassLoader(true); } result.add(pluginDescriptor); if (progress != null) { progress.showProgress( "Plugin loaded: " + pluginDescriptor.getName(), PLUGINS_PROGRESS_MAX_VALUE * ((float) i / urls.size())); } } } } }
public boolean isHighlightingAvailable(PsiFile file) { if (myDisabledHighlightingFiles.contains(file)) return false; if (file == null || !file.isPhysical()) return false; if (file instanceof PsiCompiledElement) return false; final FileType fileType = file.getFileType(); if (fileType == StdFileTypes.GUI_DESIGNER_FORM) { return true; } // To enable T.O.D.O. highlighting return !fileType.isBinary(); }
private void validateEntryPoints() { long count = PsiManager.getInstance(myProject).getModificationTracker().getModificationCount(); if (count != myLastModificationCount) { myLastModificationCount = count; Collection<SmartRefElementPointer> collection = myPersistentEntryPoints.values(); SmartRefElementPointer[] entries = collection.toArray(new SmartRefElementPointer[collection.size()]); for (SmartRefElementPointer entry : entries) { RefElement refElement = (RefElement) entry.getRefElement(); if (refElement != null && !refElement.isValid()) { myPersistentEntryPoints.remove(entry.getFQName()); } } final Iterator<RefElement> it = myTemporaryEntryPoints.iterator(); while (it.hasNext()) { RefElement refElement = it.next(); if (!refElement.isValid()) { it.remove(); } } } }
public static <T> void assertOrderedCollection( Collection<? extends T> collection, Consumer<T>... checkers) { Assert.assertNotNull(collection); if (collection.size() != checkers.length) { Assert.fail(toString(collection)); } int i = 0; for (final T actual : collection) { try { checkers[i].consume(actual); } catch (AssertionFailedError e) { System.out.println(i + ": " + actual); throw e; } i++; } }
public static void loadDisabledPlugins( final String configPath, final Collection<String> disabledPlugins) { final File file = new File(configPath, DISABLED_PLUGINS_FILENAME); if (file.isFile()) { try { BufferedReader reader = new BufferedReader(new FileReader(file)); try { String id; while ((id = reader.readLine()) != null) { disabledPlugins.add(id.trim()); } } finally { reader.close(); } } catch (IOException ignored) { } } }
private static String parseRefs( SymbolicRefsI refs, Collection<String> currentRefs, List<String> locals, List<String> remotes, List<String> tags) { if (refs == null) return null; for (String ref : currentRefs) { final SymbolicRefs.Kind kind = refs.getKind(ref); if (SymbolicRefs.Kind.LOCAL.equals(kind)) { locals.add(ref); } else if (SymbolicRefs.Kind.REMOTE.equals(kind)) { remotes.add(ref); } else { tags.add(ref); } } if (refs.getCurrent() != null && currentRefs.contains(refs.getCurrent().getName())) return refs.getCurrent().getName(); return null; }
public boolean setHostInjectionEnabled( final PsiLanguageInjectionHost host, final Collection<String> languages, final boolean enabled) { final ArrayList<BaseInjection> originalInjections = new ArrayList<BaseInjection>(); final ArrayList<BaseInjection> newInjections = new ArrayList<BaseInjection>(); for (String supportId : getAllInjectorIds()) { for (BaseInjection injection : getInjections(supportId)) { if (!languages.contains(injection.getInjectedLanguageId())) continue; boolean replace = false; final ArrayList<InjectionPlace> newPlaces = new ArrayList<InjectionPlace>(); for (InjectionPlace place : injection.getInjectionPlaces()) { if (place.isEnabled() != enabled && place.getElementPattern() != null && (place.getElementPattern().accepts(host) || place.getElementPattern().accepts(host.getParent()))) { newPlaces.add(new InjectionPlace(place.getText(), place.getElementPattern(), enabled)); replace = true; } else newPlaces.add(place); } if (replace) { originalInjections.add(injection); final BaseInjection newInjection = injection.copy(); newInjection.getInjectionPlaces().clear(); newInjection.getInjectionPlaces().addAll(newPlaces); newInjections.add(newInjection); } } } if (!originalInjections.isEmpty()) { replaceInjectionsWithUndo( host.getProject(), newInjections, originalInjections, Collections.<PsiElement>emptyList()); return true; } return false; }
public static void assertEmpty(final Collection<?> collection) { assertEmpty(collection.toString(), collection); }
public static void assertSize(int expectedSize, final Collection<?> c) { assertEquals(toString(c), expectedSize, c.size()); }
public static <T> T assertOneElement(Collection<T> collection) { Assert.assertNotNull(collection); Assert.assertEquals(toString(collection), 1, collection.size()); return collection.iterator().next(); }
public static void assertNotEmpty(final Collection<?> collection) { if (collection == null) return; assertTrue(!collection.isEmpty()); }
public static void hashesWithParents( Project project, FilePath path, final AsynchConsumer<CommitHashPlusParents> consumer, final Getter<Boolean> isCanceled, Collection<VirtualFile> paths, final String... parameters) throws VcsException { // adjust path using change manager path = getLastCommitName(project, path); final VirtualFile root = GitUtil.getGitRoot(path); final GitLineHandler h = new GitLineHandler(project, root, GitCommand.LOG); final GitLogParser parser = new GitLogParser( project, GitLogParser.NameStatus.NAME, SHORT_HASH, COMMIT_TIME, SHORT_PARENTS, AUTHOR_NAME); h.setNoSSH(true); h.setStdoutSuppressed(true); h.addParameters(parameters); h.addParameters(parser.getPretty(), "--encoding=UTF-8", "--full-history"); if (paths != null && !paths.isEmpty()) { h.endOptions(); h.addRelativeFiles(paths); } else { h.addParameters("--sparse"); h.endOptions(); h.addRelativePaths(path); } final Semaphore semaphore = new Semaphore(); h.addLineListener( new GitLineHandlerListener() { @Override public void onLineAvailable(final String line, final Key outputType) { try { if (ProcessOutputTypes.STDOUT.equals(outputType)) { if (isCanceled != null && isCanceled.get()) { h.cancel(); return; } GitLogRecord record = parser.parseOneRecord(line); consumer.consume( new CommitHashPlusParents( record.getShortHash(), record.getParentsShortHashes(), record.getLongTimeStamp() * 1000, record.getAuthorName())); } } catch (ProcessCanceledException e) { h.cancel(); semaphore.up(); } } @Override public void processTerminated(int exitCode) { semaphore.up(); } @Override public void startFailed(Throwable exception) { semaphore.up(); } }); semaphore.down(); h.start(); semaphore.waitFor(); consumer.finished(); }
public static void historyWithLinks( final Project project, FilePath path, @Nullable final SymbolicRefsI refs, @NotNull final AsynchConsumer<GitCommit> gitCommitConsumer, @Nullable final Getter<Boolean> isCanceled, @Nullable Collection<VirtualFile> paths, final String... parameters) throws VcsException { // adjust path using change manager path = getLastCommitName(project, path); final VirtualFile root = GitUtil.getGitRoot(path); final GitLineHandler h = new GitLineHandler(project, root, GitCommand.LOG); final GitLogParser parser = new GitLogParser( project, GitLogParser.NameStatus.STATUS, SHORT_HASH, HASH, COMMIT_TIME, AUTHOR_NAME, AUTHOR_TIME, AUTHOR_EMAIL, COMMITTER_NAME, COMMITTER_EMAIL, SHORT_PARENTS, REF_NAMES, SUBJECT, BODY, RAW_BODY); h.setNoSSH(true); h.setStdoutSuppressed(true); h.addParameters(parameters); h.addParameters("--name-status", parser.getPretty(), "--encoding=UTF-8", "--full-history"); if (paths != null && !paths.isEmpty()) { h.endOptions(); h.addRelativeFiles(paths); } else { h.addParameters("--sparse"); h.endOptions(); h.addRelativePaths(path); } final VcsException[] exc = new VcsException[1]; final Semaphore semaphore = new Semaphore(); final StringBuilder sb = new StringBuilder(); final Ref<Boolean> skipFirst = new Ref<Boolean>(true); h.addLineListener( new GitLineHandlerAdapter() { @Override public void onLineAvailable(final String line, final Key outputType) { try { if (ProcessOutputTypes.STDOUT.equals(outputType)) { if (isCanceled != null && isCanceled.get()) { h.cancel(); return; } // if (line.charAt(line.length() - 1) != '\u0003') { if ((!line.startsWith("\u0001")) || skipFirst.get()) { if (sb.length() > 0) { sb.append("\n"); } sb.append(line); skipFirst.set(false); return; } takeLine(project, line, sb, parser, refs, root, exc, h, gitCommitConsumer); } } catch (ProcessCanceledException e) { h.cancel(); semaphore.up(); } } @Override public void processTerminated(int exitCode) { semaphore.up(); } @Override public void startFailed(Throwable exception) { semaphore.up(); } }); semaphore.down(); h.start(); semaphore.waitFor(); takeLine(project, "", sb, parser, refs, root, exc, h, gitCommitConsumer); gitCommitConsumer.finished(); if (exc[0] != null) { throw exc[0]; } }
@NotNull private Set<PsiFile> getInjectedPsiFiles( @NotNull final List<PsiElement> elements1, @NotNull final List<PsiElement> elements2, @NotNull final ProgressIndicator progress) { ApplicationManager.getApplication().assertReadAccessAllowed(); final Set<PsiFile> outInjected = new THashSet<PsiFile>(); List<DocumentWindow> injected = InjectedLanguageUtil.getCachedInjectedDocuments(myFile); final Collection<PsiElement> hosts = new THashSet<PsiElement>(elements1.size() + elements2.size() + injected.size()); // rehighlight all injected PSI regardless the range, // since change in one place can lead to invalidation of injected PSI in (completely) other // place. for (DocumentWindow documentRange : injected) { progress.checkCanceled(); if (!documentRange.isValid()) continue; PsiFile file = PsiDocumentManager.getInstance(myProject).getPsiFile(documentRange); if (file == null) continue; PsiElement context = InjectedLanguageManager.getInstance(file.getProject()).getInjectionHost(file); if (context != null && context.isValid() && !file.getProject().isDisposed() && (myUpdateAll || myRestrictRange.intersects(context.getTextRange()))) { hosts.add(context); } } InjectedLanguageManagerImpl injectedLanguageManager = InjectedLanguageManagerImpl.getInstanceImpl(myProject); Processor<PsiElement> collectInjectableProcessor = new CommonProcessors.CollectProcessor<PsiElement>(hosts); injectedLanguageManager.processInjectableElements(elements1, collectInjectableProcessor); injectedLanguageManager.processInjectableElements(elements2, collectInjectableProcessor); final PsiLanguageInjectionHost.InjectedPsiVisitor visitor = new PsiLanguageInjectionHost.InjectedPsiVisitor() { @Override public void visit( @NotNull PsiFile injectedPsi, @NotNull List<PsiLanguageInjectionHost.Shred> places) { synchronized (outInjected) { outInjected.add(injectedPsi); } } }; if (!JobLauncher.getInstance() .invokeConcurrentlyUnderProgress( new ArrayList<PsiElement>(hosts), progress, true, new Processor<PsiElement>() { @Override public boolean process(PsiElement element) { ApplicationManager.getApplication().assertReadAccessAllowed(); progress.checkCanceled(); InjectedLanguageUtil.enumerate(element, myFile, false, visitor); return true; } })) { throw new ProcessCanceledException(); } synchronized (outInjected) { return outInjected; } }
private boolean addInjectedPsiHighlights( @NotNull PsiFile injectedPsi, TextAttributes injectedAttributes, @NotNull Collection<HighlightInfo> outInfos, @NotNull ProgressIndicator progress, @NotNull InjectedLanguageManager injectedLanguageManager) { DocumentWindow documentWindow = (DocumentWindow) PsiDocumentManager.getInstance(myProject).getCachedDocument(injectedPsi); if (documentWindow == null) return true; Place places = InjectedLanguageUtil.getShreds(injectedPsi); for (PsiLanguageInjectionHost.Shred place : places) { PsiLanguageInjectionHost host = place.getHost(); if (host == null) continue; TextRange textRange = place.getRangeInsideHost().shiftRight(host.getTextRange().getStartOffset()); if (textRange.isEmpty()) continue; String desc = injectedPsi.getLanguage().getDisplayName() + ": " + injectedPsi.getText(); HighlightInfo.Builder builder = HighlightInfo.newHighlightInfo(HighlightInfoType.INJECTED_LANGUAGE_BACKGROUND) .range(textRange); if (injectedAttributes != null && InjectedLanguageUtil.isHighlightInjectionBackground(host)) { builder.textAttributes(injectedAttributes); } builder.unescapedToolTip(desc); HighlightInfo info = builder.createUnconditionally(); info.setFromInjection(true); outInfos.add(info); } HighlightInfoHolder holder = createInfoHolder(injectedPsi); runHighlightVisitorsForInjected(injectedPsi, holder, progress); for (int i = 0; i < holder.size(); i++) { HighlightInfo info = holder.get(i); final int startOffset = documentWindow.injectedToHost(info.startOffset); final TextRange fixedTextRange = getFixedTextRange(documentWindow, startOffset); addPatchedInfos( info, injectedPsi, documentWindow, injectedLanguageManager, fixedTextRange, outInfos); } int injectedStart = holder.size(); highlightInjectedSyntax(injectedPsi, holder); for (int i = injectedStart; i < holder.size(); i++) { HighlightInfo info = holder.get(i); final int startOffset = info.startOffset; final TextRange fixedTextRange = getFixedTextRange(documentWindow, startOffset); if (fixedTextRange == null) { info.setFromInjection(true); outInfos.add(info); } else { HighlightInfo patched = new HighlightInfo( info.forcedTextAttributes, info.forcedTextAttributesKey, info.type, fixedTextRange.getStartOffset(), fixedTextRange.getEndOffset(), info.getDescription(), info.getToolTip(), info.type.getSeverity(null), info.isAfterEndOfLine(), null, false, 0, info.getProblemGroup(), info.getGutterIconRenderer()); patched.setFromInjection(true); outInfos.add(patched); } } if (!isDumbMode()) { List<HighlightInfo> todos = new ArrayList<HighlightInfo>(); highlightTodos( injectedPsi, injectedPsi.getText(), 0, injectedPsi.getTextLength(), progress, myPriorityRange, todos, todos); for (HighlightInfo info : todos) { addPatchedInfos(info, injectedPsi, documentWindow, injectedLanguageManager, null, outInfos); } } advanceProgress(1); return true; }
private static void addPatchedInfos( @NotNull HighlightInfo info, @NotNull PsiFile injectedPsi, @NotNull DocumentWindow documentWindow, @NotNull InjectedLanguageManager injectedLanguageManager, @Nullable TextRange fixedTextRange, @NotNull Collection<HighlightInfo> out) { ProperTextRange textRange = new ProperTextRange(info.startOffset, info.endOffset); List<TextRange> editables = injectedLanguageManager.intersectWithAllEditableFragments(injectedPsi, textRange); for (TextRange editable : editables) { TextRange hostRange = fixedTextRange == null ? documentWindow.injectedToHost(editable) : fixedTextRange; boolean isAfterEndOfLine = info.isAfterEndOfLine(); if (isAfterEndOfLine) { // convert injected afterEndOfLine to either host' 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.type.getSeverity(null), isAfterEndOfLine, null, false, 0, info.getProblemGroup(), info.getGutterIconRenderer()); patched.setHint(info.hasHint()); if (info.quickFixActionRanges != null) { for (Pair<HighlightInfo.IntentionActionDescriptor, TextRange> pair : info.quickFixActionRanges) { TextRange quickfixTextRange = pair.getSecond(); List<TextRange> editableQF = injectedLanguageManager.intersectWithAllEditableFragments( injectedPsi, quickfixTextRange); for (TextRange editableRange : editableQF) { HighlightInfo.IntentionActionDescriptor descriptor = pair.getFirst(); if (patched.quickFixActionRanges == null) patched.quickFixActionRanges = new ArrayList<Pair<HighlightInfo.IntentionActionDescriptor, TextRange>>(); TextRange hostEditableRange = documentWindow.injectedToHost(editableRange); patched.quickFixActionRanges.add(Pair.create(descriptor, hostEditableRange)); } } } patched.setFromInjection(true); out.add(patched); } }