// returns (injected psi, leaf element at the offset, language of the leaf element) // since findElementAt() is expensive, we trying to reuse its result @NotNull private static Trinity<PsiElement, PsiElement, Language> tryOffset( @NotNull PsiFile hostFile, final int offset, @NotNull PsiDocumentManager documentManager) { FileViewProvider provider = hostFile.getViewProvider(); Language leafLanguage = null; PsiElement leafElement = null; for (Language language : provider.getLanguages()) { PsiElement element = provider.findElementAt(offset, language); if (element != null) { if (leafLanguage == null) { leafLanguage = language; leafElement = element; } PsiElement injected = findInside(element, hostFile, offset, documentManager); if (injected != null) return Trinity.create(injected, element, language); } // maybe we are at the border between two psi elements, then try to find injection at the end // of the left element if (offset != 0 && (element == null || element.getTextRange().getStartOffset() == offset)) { PsiElement leftElement = provider.findElementAt(offset - 1, language); if (leftElement != null && leftElement.getTextRange().getEndOffset() == offset) { PsiElement injected = findInside(leftElement, hostFile, offset, documentManager); if (injected != null) return Trinity.create(injected, element, language); } } } return Trinity.create(null, leafElement, leafLanguage); }
public static ValueHint createValueHint( Project project, Editor editor, Point point, ValueHintType type) { Trinity<PsiElement, TextRange, Value> trinity = getSelectedExpression(project, editor, point, type); final ValueHint hint = new ValueHint(project, editor, point, type, trinity.getFirst(), trinity.getSecond()); hint.myValueToShow = trinity.getThird(); return hint; }
private void highlightInjectedSyntax(final PsiFile injectedPsi, HighlightInfoHolder holder) { List<Trinity<IElementType, PsiLanguageInjectionHost, TextRange>> tokens = InjectedLanguageUtil.getHighlightTokens(injectedPsi); if (tokens == null) return; final Language injectedLanguage = injectedPsi.getLanguage(); Project project = injectedPsi.getProject(); SyntaxHighlighter syntaxHighlighter = SyntaxHighlighterFactory.getSyntaxHighlighter( injectedLanguage, project, injectedPsi.getVirtualFile()); final TextAttributes defaultAttrs = myGlobalScheme.getAttributes(HighlighterColors.TEXT); for (Trinity<IElementType, PsiLanguageInjectionHost, TextRange> token : tokens) { ProgressManager.checkCanceled(); IElementType tokenType = token.getFirst(); PsiLanguageInjectionHost injectionHost = token.getSecond(); TextRange textRange = token.getThird(); TextAttributesKey[] keys = syntaxHighlighter.getTokenHighlights(tokenType); if (textRange.getLength() == 0) continue; TextRange annRange = textRange.shiftRight(injectionHost.getTextRange().getStartOffset()); // force attribute colors to override host' ones TextAttributes attributes = null; for (TextAttributesKey key : keys) { TextAttributes attrs2 = myGlobalScheme.getAttributes(key); if (attrs2 != null) { attributes = attributes == null ? attrs2 : TextAttributes.merge(attributes, attrs2); } } TextAttributes forcedAttributes; if (attributes == null || attributes.isEmpty() || attributes.equals(defaultAttrs)) { forcedAttributes = TextAttributes.ERASE_MARKER; } else { Color back = attributes.getBackgroundColor() == null ? myGlobalScheme.getDefaultBackground() : attributes.getBackgroundColor(); Color fore = attributes.getForegroundColor() == null ? myGlobalScheme.getDefaultForeground() : attributes.getForegroundColor(); forcedAttributes = new TextAttributes( fore, back, attributes.getEffectColor(), attributes.getEffectType(), attributes.getFontType()); } HighlightInfo info = HighlightInfo.createHighlightInfo( HighlightInfoType.INJECTED_LANGUAGE_FRAGMENT, annRange, null, null, forcedAttributes); holder.add(info); } }
public void initMarkers(Place shreds) { SmartPointerManager smartPointerManager = SmartPointerManager.getInstance(myProject); int curOffset = -1; for (PsiLanguageInjectionHost.Shred shred : shreds) { final RangeMarker rangeMarker = myNewDocument.createRangeMarker( shred.getRange().getStartOffset() + shred.getPrefix().length(), shred.getRange().getEndOffset() - shred.getSuffix().length()); final TextRange rangeInsideHost = shred.getRangeInsideHost(); PsiLanguageInjectionHost host = shred.getHost(); RangeMarker origMarker = myOrigDocument.createRangeMarker( rangeInsideHost.shiftRight(host.getTextRange().getStartOffset())); SmartPsiElementPointer<PsiLanguageInjectionHost> elementPointer = smartPointerManager.createSmartPsiElementPointer(host); Trinity<RangeMarker, RangeMarker, SmartPsiElementPointer> markers = Trinity.<RangeMarker, RangeMarker, SmartPsiElementPointer>create( origMarker, rangeMarker, elementPointer); myMarkers.add(markers); origMarker.setGreedyToRight(true); rangeMarker.setGreedyToRight(true); if (origMarker.getStartOffset() > curOffset) { origMarker.setGreedyToLeft(true); rangeMarker.setGreedyToLeft(true); } curOffset = origMarker.getEndOffset(); } initGuardedBlocks(shreds); }
@NotNull private GroovyResolveResult[] doPolyResolveWithCaching( final boolean incompleteCode, final boolean genericsMatter) { final InferenceContext context = TypeInferenceHelper.getCurrentContext(); final Trinity<?, ?, ?> key = Trinity.create(this, context, Pair.create(incompleteCode, genericsMatter)); final GroovyResolveResult[] value = RecursionManager.doPreventingRecursion( key, true, new Computable<GroovyResolveResult[]>() { @Override public GroovyResolveResult[] compute() { return doPolyResolve(incompleteCode, genericsMatter); } }); return value == null ? GroovyResolveResult.EMPTY_ARRAY : value; }
@NotNull private Pair<Boolean, GroovyResolveResult[]> resolveByShape( final boolean allVariants, @Nullable final GrExpression upToArgument) { LOG.assertTrue(allVariants || upToArgument == null); final Trinity key = Trinity.create( TypeInferenceHelper.getCurrentContext(), this, Pair.create(allVariants, upToArgument)); final Pair<Boolean, GroovyResolveResult[]> result = RecursionManager.doPreventingRecursion( key, true, new Computable<Pair<Boolean, GroovyResolveResult[]>>() { @Override public Pair<Boolean, GroovyResolveResult[]> compute() { return doResolveByShape(allVariants, upToArgument); } }); return result == null ? Pair.create(false, GroovyResolveResult.EMPTY_ARRAY) : result; }
@Nullable private <TRef extends PsiReference, TResult> TResult resolve( @NotNull final TRef ref, @NotNull final AbstractResolver<TRef, TResult> resolver, boolean needToPreventRecursion, final boolean incompleteCode, boolean isPoly, boolean isPhysical) { ProgressIndicatorProvider.checkCanceled(); if (isPhysical) { ApplicationManager.getApplication().assertReadAccessAllowed(); } int index = getIndex(isPhysical, incompleteCode, isPoly); ConcurrentMap<TRef, TResult> map = getMap(index); TResult result = map.get(ref); if (result != null) { return result; } RecursionGuard.StackStamp stamp = myGuard.markStack(); result = needToPreventRecursion ? myGuard.doPreventingRecursion( Trinity.create(ref, incompleteCode, isPoly), true, new Computable<TResult>() { @Override public TResult compute() { return resolver.resolve(ref, incompleteCode); } }) : resolver.resolve(ref, incompleteCode); PsiElement element = result instanceof ResolveResult ? ((ResolveResult) result).getElement() : null; LOG.assertTrue(element == null || element.isValid(), result); if (stamp.mayCacheNow()) { cache(ref, map, result); } return result; }
private static Trinity<PsiElement, TextRange, Value> getSelectedExpression( final Project project, final Editor editor, final Point point, final ValueHintType type) { final Ref<PsiElement> selectedExpression = Ref.create(null); final Ref<TextRange> currentRange = Ref.create(null); final Ref<Value> preCalculatedValue = Ref.create(null); PsiDocumentManager.getInstance(project) .commitAndRunReadAction( new Runnable() { public void run() { // Point -> offset final int offset = calculateOffset(editor, point); PsiFile psiFile = PsiDocumentManager.getInstance(project).getPsiFile(editor.getDocument()); if (psiFile == null || !psiFile.isValid()) return; int selectionStart = editor.getSelectionModel().getSelectionStart(); int selectionEnd = editor.getSelectionModel().getSelectionEnd(); if ((type == ValueHintType.MOUSE_CLICK_HINT || type == ValueHintType.MOUSE_ALT_OVER_HINT) && (selectionStart <= offset && offset <= selectionEnd)) { PsiElement ctx = (selectionStart > 0) ? psiFile.findElementAt(selectionStart - 1) : psiFile.findElementAt(selectionStart); try { String text = editor.getSelectionModel().getSelectedText(); if (text != null && ctx != null) { selectedExpression.set( JVMElementFactories.getFactory(ctx.getLanguage(), project) .createExpressionFromText(text, ctx)); currentRange.set( new TextRange( editor.getSelectionModel().getSelectionStart(), editor.getSelectionModel().getSelectionEnd())); } } catch (IncorrectOperationException ignored) { } } if (currentRange.get() == null) { PsiElement elementAtCursor = psiFile.findElementAt(offset); if (elementAtCursor == null) { return; } Pair<PsiElement, TextRange> pair = findExpression( elementAtCursor, type == ValueHintType.MOUSE_CLICK_HINT || type == ValueHintType.MOUSE_ALT_OVER_HINT); if (pair == null) { if (type == ValueHintType.MOUSE_OVER_HINT) { final DebuggerSession debuggerSession = DebuggerManagerEx.getInstanceEx(project) .getContext() .getDebuggerSession(); if (debuggerSession != null && debuggerSession.isPaused()) { final Pair<Method, Value> lastExecuted = debuggerSession.getProcess().getLastExecutedMethod(); if (lastExecuted != null) { final Method method = lastExecuted.getFirst(); if (method != null) { final Pair<PsiElement, TextRange> expressionPair = findExpression(elementAtCursor, true); if (expressionPair != null && expressionPair.getFirst() instanceof PsiMethodCallExpression) { final PsiMethodCallExpression methodCallExpression = (PsiMethodCallExpression) expressionPair.getFirst(); final PsiMethod psiMethod = methodCallExpression.resolveMethod(); if (psiMethod != null) { final JVMName jvmSignature = JVMNameUtil.getJVMSignature(psiMethod); try { if (method.name().equals(psiMethod.getName()) && method .signature() .equals( jvmSignature.getName(debuggerSession.getProcess()))) { pair = expressionPair; preCalculatedValue.set(lastExecuted.getSecond()); } } catch (EvaluateException ignored) { } } } } } } } } if (pair == null) { return; } selectedExpression.set(pair.getFirst()); currentRange.set(pair.getSecond()); } } }); return Trinity.create(selectedExpression.get(), currentRange.get(), preCalculatedValue.get()); }