Temporary disable kotlin language support
[idea/community.git] / plugins / stream-debugger / src / main / java / com / intellij / debugger / streams / action / TraceStreamAction.java
1 /*
2  * Copyright 2000-2017 JetBrains s.r.o.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 package com.intellij.debugger.streams.action;
17
18 import com.intellij.debugger.engine.evaluation.EvaluationContextImpl;
19 import com.intellij.debugger.streams.diagnostic.ex.TraceCompilationException;
20 import com.intellij.debugger.streams.diagnostic.ex.TraceEvaluationException;
21 import com.intellij.debugger.streams.lib.LibraryManager;
22 import com.intellij.debugger.streams.psi.DebuggerPositionResolver;
23 import com.intellij.debugger.streams.psi.impl.DebuggerPositionResolverImpl;
24 import com.intellij.debugger.streams.psi.impl.JavaChainTransformerImpl;
25 import com.intellij.debugger.streams.psi.impl.JavaStreamChainBuilder;
26 import com.intellij.debugger.streams.psi.impl.StreamChainOption;
27 import com.intellij.debugger.streams.trace.*;
28 import com.intellij.debugger.streams.trace.dsl.impl.DslImpl;
29 import com.intellij.debugger.streams.trace.dsl.impl.java.JavaStatementFactory;
30 import com.intellij.debugger.streams.trace.impl.JavaTraceExpressionBuilder;
31 import com.intellij.debugger.streams.trace.impl.TraceResultInterpreterImpl;
32 import com.intellij.debugger.streams.ui.impl.ElementChooserImpl;
33 import com.intellij.debugger.streams.ui.impl.EvaluationAwareTraceWindow;
34 import com.intellij.debugger.streams.wrapper.StreamChain;
35 import com.intellij.debugger.streams.wrapper.StreamChainBuilder;
36 import com.intellij.openapi.actionSystem.AnAction;
37 import com.intellij.openapi.actionSystem.AnActionEvent;
38 import com.intellij.openapi.application.ApplicationManager;
39 import com.intellij.openapi.diagnostic.Logger;
40 import com.intellij.openapi.editor.Editor;
41 import com.intellij.openapi.project.Project;
42 import com.intellij.psi.PsiElement;
43 import com.intellij.psi.util.PsiEditorUtil;
44 import com.intellij.xdebugger.XDebugSession;
45 import com.intellij.xdebugger.XDebuggerManager;
46 import org.jetbrains.annotations.NotNull;
47 import org.jetbrains.annotations.Nullable;
48
49 import java.util.Collections;
50 import java.util.List;
51 import java.util.stream.Collectors;
52
53 /**
54  * @author Vitaliy.Bibaev
55  */
56 public class TraceStreamAction extends AnAction {
57   private static final Logger LOG = Logger.getInstance(TraceStreamAction.class);
58
59   private final DebuggerPositionResolver myPositionResolver = new DebuggerPositionResolverImpl();
60   private final List<StreamChainBuilder> myChainBuilders =
61     Collections.singletonList(new JavaStreamChainBuilder(new JavaChainTransformerImpl()));
62
63   @Override
64   public void update(@NotNull AnActionEvent e) {
65     final XDebugSession session = getCurrentSession(e);
66     final PsiElement element = session == null ? null : myPositionResolver.getNearestElementToBreakpoint(session);
67     e.getPresentation().setEnabled(element != null && isChainExists(element));
68   }
69
70   @Override
71   public void actionPerformed(@NotNull AnActionEvent e) {
72     final XDebugSession session = getCurrentSession(e);
73     final PsiElement element = session == null ? null : myPositionResolver.getNearestElementToBreakpoint(session);
74     if (element != null) {
75       final List<StreamChain> chains = myChainBuilders.stream()
76         .filter(builder -> builder.isChainExists(element))
77         .flatMap(builder -> builder.build(element).stream())
78         .collect(Collectors.toList());
79       if (chains.isEmpty()) {
80         LOG.warn("stream chain is not built");
81         return;
82       }
83
84       if (chains.size() == 1) {
85         runTrace(chains.get(0), session);
86       }
87       else {
88         final Editor editor = PsiEditorUtil.Service.getInstance().findEditorByPsiElement(element);
89         if (editor == null) {
90           throw new RuntimeException("editor not found");
91         }
92
93         new MyStreamChainChooser(editor).show(chains.stream().map(StreamChainOption::new).collect(Collectors.toList()),
94                                               provider -> runTrace(provider.getChain(), session));
95       }
96     }
97     else {
98       LOG.info("element at cursor not found");
99     }
100   }
101
102   private boolean isChainExists(@NotNull PsiElement element) {
103     for (final StreamChainBuilder b : myChainBuilders) {
104       if (b.isChainExists(element)) {
105         return true;
106       }
107     }
108
109     return false;
110   }
111
112   private void runTrace(@NotNull StreamChain chain, @NotNull XDebugSession session) {
113     final EvaluationAwareTraceWindow window = new EvaluationAwareTraceWindow(session, chain);
114     ApplicationManager.getApplication().invokeLater(window::show);
115     final Project project = session.getProject();
116     final TraceExpressionBuilder expressionBuilder = new JavaTraceExpressionBuilder(project, new DslImpl(new JavaStatementFactory()));
117     final TraceResultInterpreterImpl resultInterpreter = new TraceResultInterpreterImpl(project);
118     final StreamTracer tracer = new EvaluateExpressionTracer(session, expressionBuilder, resultInterpreter);
119     tracer.trace(chain, new TracingCallback() {
120       @Override
121       public void evaluated(@NotNull TracingResult result, @NotNull EvaluationContextImpl context) {
122         final ResolvedTracingResult resolvedTrace = result.resolve(LibraryManager.getInstance(context.getProject()));
123         ApplicationManager.getApplication()
124           .invokeLater(() -> window.setTrace(resolvedTrace, context));
125       }
126
127       @Override
128       public void evaluationFailed(@NotNull String traceExpression, @NotNull String message) {
129         notifyUI(message);
130         throw new TraceEvaluationException(message, traceExpression);
131       }
132
133       @Override
134       public void compilationFailed(@NotNull String traceExpression, @NotNull String message) {
135         notifyUI(message);
136         throw new TraceCompilationException(message, traceExpression);
137       }
138
139       private void notifyUI(@NotNull String message) {
140         ApplicationManager.getApplication().invokeLater(() -> window.setFailMessage(message));
141       }
142     });
143   }
144
145   @Nullable
146   private XDebugSession getCurrentSession(@NotNull AnActionEvent e) {
147     final Project project = e.getProject();
148     return project == null ? null : XDebuggerManager.getInstance(project).getCurrentSession();
149   }
150
151   private static class MyStreamChainChooser extends ElementChooserImpl<StreamChainOption> {
152     MyStreamChainChooser(@NotNull Editor editor) {
153       super(editor);
154     }
155   }
156 }