2 * Copyright 2000-2015 JetBrains s.r.o.
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
16 package com.intellij.xdebugger.impl;
18 import com.intellij.lang.Language;
19 import com.intellij.openapi.actionSystem.CommonDataKeys;
20 import com.intellij.openapi.actionSystem.DataContext;
21 import com.intellij.openapi.application.Result;
22 import com.intellij.openapi.application.WriteAction;
23 import com.intellij.openapi.editor.Caret;
24 import com.intellij.openapi.editor.Document;
25 import com.intellij.openapi.editor.Editor;
26 import com.intellij.openapi.fileEditor.FileDocumentManager;
27 import com.intellij.openapi.fileEditor.FileEditorManager;
28 import com.intellij.openapi.fileEditor.OpenFileDescriptor;
29 import com.intellij.openapi.fileTypes.StdFileTypes;
30 import com.intellij.openapi.project.Project;
31 import com.intellij.openapi.util.text.StringUtil;
32 import com.intellij.openapi.vfs.VirtualFile;
33 import com.intellij.psi.*;
34 import com.intellij.psi.impl.source.tree.injected.InjectedLanguageUtil;
35 import com.intellij.psi.util.PsiTreeUtil;
36 import com.intellij.util.Processor;
37 import com.intellij.xdebugger.*;
38 import com.intellij.xdebugger.breakpoints.*;
39 import com.intellij.xdebugger.breakpoints.ui.XBreakpointGroupingRule;
40 import com.intellij.xdebugger.evaluation.EvaluationMode;
41 import com.intellij.xdebugger.evaluation.XDebuggerEvaluator;
42 import com.intellij.xdebugger.frame.XExecutionStack;
43 import com.intellij.xdebugger.frame.XStackFrame;
44 import com.intellij.xdebugger.frame.XSuspendContext;
45 import com.intellij.xdebugger.frame.XValueContainer;
46 import com.intellij.xdebugger.impl.breakpoints.XBreakpointUtil;
47 import com.intellij.xdebugger.impl.breakpoints.XExpressionImpl;
48 import com.intellij.xdebugger.impl.breakpoints.ui.grouping.XBreakpointFileGroupingRule;
49 import com.intellij.xdebugger.impl.evaluate.quick.common.ValueLookupManager;
50 import com.intellij.xdebugger.impl.settings.XDebuggerSettingsManager;
51 import com.intellij.xdebugger.impl.ui.tree.actions.XDebuggerTreeActionBase;
52 import com.intellij.xdebugger.settings.XDebuggerSettings;
53 import gnu.trove.THashMap;
54 import org.jetbrains.annotations.NotNull;
55 import org.jetbrains.annotations.Nullable;
62 public class XDebuggerUtilImpl extends XDebuggerUtil {
63 private XLineBreakpointType<?>[] myLineBreakpointTypes;
64 private Map<Class<? extends XBreakpointType>, XBreakpointType<?,?>> myBreakpointTypeByClass;
67 public XLineBreakpointType<?>[] getLineBreakpointTypes() {
68 if (myLineBreakpointTypes == null) {
69 XBreakpointType[] types = XBreakpointUtil.getBreakpointTypes();
70 List<XLineBreakpointType<?>> lineBreakpointTypes = new ArrayList<XLineBreakpointType<?>>();
71 for (XBreakpointType type : types) {
72 if (type instanceof XLineBreakpointType<?>) {
73 lineBreakpointTypes.add((XLineBreakpointType<?>)type);
76 myLineBreakpointTypes = lineBreakpointTypes.toArray(new XLineBreakpointType<?>[lineBreakpointTypes.size()]);
78 return myLineBreakpointTypes;
82 public void toggleLineBreakpoint(@NotNull final Project project, @NotNull final VirtualFile file, final int line, boolean temporary) {
83 XLineBreakpointType<?> typeWinner = null;
84 for (XLineBreakpointType<?> type : getLineBreakpointTypes()) {
85 if (type.canPutAt(file, line, project) && (typeWinner == null || type.getPriority() > typeWinner.getPriority())) {
89 if (typeWinner != null) {
90 toggleLineBreakpoint(project, typeWinner, file, line, temporary);
95 public boolean canPutBreakpointAt(@NotNull Project project, @NotNull VirtualFile file, int line) {
96 for (XLineBreakpointType<?> type : getLineBreakpointTypes()) {
97 if (type.canPutAt(file, line, project)) {
105 public <P extends XBreakpointProperties> void toggleLineBreakpoint(@NotNull final Project project,
106 @NotNull final XLineBreakpointType<P> type,
107 @NotNull final VirtualFile file,
109 final boolean temporary) {
110 toggleAndReturnLineBreakpoint(project, type, file, line, temporary);
113 public static <P extends XBreakpointProperties> XLineBreakpoint toggleAndReturnLineBreakpoint(@NotNull final Project project,
114 @NotNull final XLineBreakpointType<P> type,
115 @NotNull final VirtualFile file,
117 final boolean temporary) {
118 return new WriteAction<XLineBreakpoint>() {
120 protected void run(@NotNull final Result<XLineBreakpoint> result) {
121 XBreakpointManager breakpointManager = XDebuggerManager.getInstance(project).getBreakpointManager();
122 XLineBreakpoint<P> breakpoint = breakpointManager.findBreakpointAtLine(type, file, line);
123 if (breakpoint != null) {
124 breakpointManager.removeBreakpoint(breakpoint);
127 P properties = type.createBreakpointProperties(file, line);
128 result.setResult(breakpointManager.addLineBreakpoint(type, file.getUrl(), line, properties, temporary));
131 }.execute().getResultObject();
135 public void removeBreakpoint(final Project project, final XBreakpoint<?> breakpoint) {
138 protected void run(@NotNull final Result result) {
139 XDebuggerManager.getInstance(project).getBreakpointManager().removeBreakpoint(breakpoint);
145 public <B extends XBreakpoint<?>> XBreakpointType<B, ?> findBreakpointType(@NotNull Class<? extends XBreakpointType<B, ?>> typeClass) {
146 if (myBreakpointTypeByClass == null) {
147 myBreakpointTypeByClass = new THashMap<Class<? extends XBreakpointType>, XBreakpointType<?,?>>();
148 for (XBreakpointType<?, ?> breakpointType : XBreakpointUtil.getBreakpointTypes()) {
149 myBreakpointTypeByClass.put(breakpointType.getClass(), breakpointType);
152 XBreakpointType<?, ?> type = myBreakpointTypeByClass.get(typeClass);
153 //noinspection unchecked
154 return (XBreakpointType<B, ?>)type;
158 public <T extends XDebuggerSettings<?>> T getDebuggerSettings(Class<T> aClass) {
159 return XDebuggerSettingsManager.getInstanceImpl().getSettings(aClass);
163 public XValueContainer getValueContainer(DataContext dataContext) {
164 return XDebuggerTreeActionBase.getSelectedValue(dataContext);
169 public XSourcePosition createPosition(final VirtualFile file, final int line) {
170 return XSourcePositionImpl.create(file, line);
175 public XSourcePosition createPositionByOffset(final VirtualFile file, final int offset) {
176 return XSourcePositionImpl.createByOffset(file, offset);
180 public <B extends XLineBreakpoint<?>> XBreakpointGroupingRule<B, ?> getGroupingByFileRule() {
181 return new XBreakpointFileGroupingRule<B>();
185 public static XSourcePosition getCaretPosition(@NotNull Project project, DataContext context) {
186 Editor editor = getEditor(project, context);
187 if (editor == null) return null;
189 final Document document = editor.getDocument();
190 final int line = editor.getCaretModel().getLogicalPosition().line;
191 VirtualFile file = FileDocumentManager.getInstance().getFile(document);
192 return XSourcePositionImpl.create(file, line);
196 public static Collection<XSourcePosition> getAllCaretsPositions(@NotNull Project project, DataContext context) {
197 Editor editor = getEditor(project, context);
198 if (editor == null) {
199 return Collections.emptyList();
202 final Document document = editor.getDocument();
203 VirtualFile file = FileDocumentManager.getInstance().getFile(document);
204 Collection<XSourcePosition> res = new ArrayList<XSourcePosition>();
205 List<Caret> carets = editor.getCaretModel().getAllCarets();
206 for (Caret caret : carets) {
207 int line = caret.getLogicalPosition().line;
208 XSourcePositionImpl position = XSourcePositionImpl.create(file, line);
209 if (position != null) {
217 private static Editor getEditor(@NotNull Project project, DataContext context) {
218 Editor editor = CommonDataKeys.EDITOR.getData(context);
220 return FileEditorManager.getInstance(project).getSelectedTextEditor();
226 public <B extends XBreakpoint<?>> Comparator<B> getDefaultBreakpointComparator(final XBreakpointType<B, ?> type) {
227 return new Comparator<B>() {
229 public int compare(final B o1, final B o2) {
230 return type.getDisplayText(o1).compareTo(type.getDisplayText(o2));
236 public <P extends XBreakpointProperties> Comparator<XLineBreakpoint<P>> getDefaultLineBreakpointComparator() {
237 return new Comparator<XLineBreakpoint<P>>() {
239 public int compare(final XLineBreakpoint<P> o1, final XLineBreakpoint<P> o2) {
240 int fileCompare = o1.getFileUrl().compareTo(o2.getFileUrl());
241 if (fileCompare != 0) return fileCompare;
242 return o1.getLine() - o2.getLine();
248 public static XDebuggerEvaluator getEvaluator(final XSuspendContext suspendContext) {
249 XExecutionStack executionStack = suspendContext.getActiveExecutionStack();
250 if (executionStack != null) {
251 XStackFrame stackFrame = executionStack.getTopFrame();
252 if (stackFrame != null) {
253 return stackFrame.getEvaluator();
260 public void iterateLine(@NotNull Project project, @NotNull Document document, int line, @NotNull Processor<PsiElement> processor) {
261 PsiFile file = PsiDocumentManager.getInstance(project).getPsiFile(document);
269 lineStart = document.getLineStartOffset(line);
270 lineEnd = document.getLineEndOffset(line);
272 catch (IndexOutOfBoundsException ignored) {
277 int offset = lineStart;
279 if (file instanceof PsiCompiledFile) {
280 file = ((PsiCompiledFile)file).getDecompiledPsiFile();
283 while (offset < lineEnd) {
284 element = file.findElementAt(offset);
285 if (element != null) {
286 if (!processor.process(element)) {
290 offset = element.getTextRange().getEndOffset();
300 public <B extends XLineBreakpoint<?>> List<XBreakpointGroupingRule<B, ?>> getGroupingByFileRuleAsList() {
301 return Collections.<XBreakpointGroupingRule<B, ?>>singletonList(this.<B>getGroupingByFileRule());
306 public PsiElement findContextElement(@NotNull VirtualFile virtualFile, int offset, @NotNull Project project, boolean checkXml) {
307 if (!virtualFile.isValid()) {
311 Document document = FileDocumentManager.getInstance().getDocument(virtualFile);
312 PsiFile file = document == null ? null : PsiManager.getInstance(project).findFile(virtualFile);
320 if (offset > document.getTextLength()) {
321 offset = document.getTextLength();
323 int startOffset = offset;
325 int lineEndOffset = document.getLineEndOffset(document.getLineNumber(offset));
326 PsiElement result = null;
328 PsiElement element = file.findElementAt(offset);
329 if (!(element instanceof PsiWhiteSpace) && !(element instanceof PsiComment)) {
334 offset = element.getTextRange().getEndOffset() + 1;
336 while (offset < lineEndOffset);
338 if (result == null) {
339 result = file.findElementAt(startOffset);
342 if (checkXml && result != null && StdFileTypes.XML.getLanguage().equals(result.getLanguage())) {
343 PsiLanguageInjectionHost parent = PsiTreeUtil.getParentOfType(result, PsiLanguageInjectionHost.class);
344 if (parent != null) {
345 result = InjectedLanguageUtil.findElementInInjected(parent, offset);
352 public void disableValueLookup(@NotNull Editor editor) {
353 ValueLookupManager.DISABLE_VALUE_LOOKUP.set(editor, Boolean.TRUE);
357 public static Editor createEditor(@NotNull OpenFileDescriptor descriptor) {
358 return descriptor.canNavigate() ? FileEditorManager.getInstance(descriptor.getProject()).openTextEditor(descriptor, false) : null;
361 public static void rebuildAllSessionsViews(@Nullable Project project) {
362 if (project == null) return;
363 for (XDebugSession session : XDebuggerManager.getInstance(project).getDebugSessions()) {
364 if (session.isSuspended()) {
365 session.rebuildViews();
372 public XExpression createExpression(@NotNull String text, Language language, String custom, EvaluationMode mode) {
373 return new XExpressionImpl(text, language, custom, mode);
376 public static boolean isEmptyExpression(@Nullable XExpression expression) {
377 return expression == null || StringUtil.isEmptyOrSpaces(expression.getExpression());