Don't block EDT while counting information for Resolve and Bytecode window

This commit is contained in:
Nikolay Krasko
2012-08-27 18:55:29 +04:00
parent 628da4e670
commit c788636365
4 changed files with 353 additions and 252 deletions
@@ -0,0 +1,115 @@
/*
* Copyright 2010-2012 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.jet.plugin.internal;
import com.intellij.openapi.editor.Editor;
import com.intellij.openapi.editor.ex.EditorEx;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.psi.PsiFile;
import com.intellij.psi.PsiManager;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.jet.lang.psi.JetFile;
/**
* @author Nikolay Krasko
*/
public class Location {
@Nullable
final Editor editor;
@Nullable
final JetFile jetFile;
final long modificationStamp;
final int startOffset;
final int endOffset;
private Location(@Nullable Editor editor, Project project) {
this.editor = editor;
if (editor != null) {
modificationStamp = editor.getDocument().getModificationStamp();
startOffset = editor.getSelectionModel().getSelectionStart();
endOffset = editor.getSelectionModel().getSelectionEnd();
VirtualFile vFile = ((EditorEx) editor).getVirtualFile();
if (vFile == null) {
jetFile = null;
}
else {
PsiFile psiFile = PsiManager.getInstance(project).findFile(vFile);
jetFile = psiFile instanceof JetFile ? (JetFile) psiFile : null;
}
}
else {
modificationStamp = 0;
startOffset = 0;
endOffset = 0;
jetFile = null;
}
}
public static Location fromEditor(Editor editor, Project project) {
return new Location(editor, project);
}
@Nullable
public JetFile getJetFile() {
return jetFile;
}
@Nullable
public Editor getEditor() {
return editor;
}
public int getStartOffset() {
return startOffset;
}
public int getEndOffset() {
return endOffset;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof Location)) return false;
Location location = (Location)o;
if (modificationStamp != location.modificationStamp) return false;
if (endOffset != location.endOffset) return false;
if (startOffset != location.startOffset) return false;
if (editor != null ? !editor.equals(location.editor) : location.editor != null) return false;
if (jetFile != null ? !jetFile.equals(location.jetFile) : location.jetFile != null) return false;
return true;
}
@Override
public int hashCode() {
int result = editor != null ? editor.hashCode() : 0;
result = 31 * result + (jetFile != null ? jetFile.hashCode() : 0);
result = 31 * result + (int)(modificationStamp ^ (modificationStamp >>> 32));
result = 31 * result + startOffset;
result = 31 * result + endOffset;
return result;
}
}
@@ -27,22 +27,21 @@ import com.intellij.openapi.editor.Document;
import com.intellij.openapi.editor.Editor;
import com.intellij.openapi.editor.EditorFactory;
import com.intellij.openapi.editor.ScrollType;
import com.intellij.openapi.editor.ex.EditorEx;
import com.intellij.openapi.fileEditor.FileEditorManager;
import com.intellij.openapi.progress.ProcessCanceledException;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.Comparing;
import com.intellij.openapi.util.Pair;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.psi.PsiFile;
import com.intellij.psi.PsiManager;
import com.intellij.util.Alarm;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.jet.analyzer.AnalyzeExhaust;
import org.jetbrains.jet.codegen.ClassBuilderFactories;
import org.jetbrains.jet.codegen.ClassFileFactory;
import org.jetbrains.jet.codegen.CompilationErrorHandler;
import org.jetbrains.jet.codegen.GenerationState;
import org.jetbrains.jet.lang.psi.JetFile;
import org.jetbrains.jet.plugin.internal.Location;
import org.jetbrains.jet.plugin.project.WholeProjectAnalyzerFacade;
import org.jetbrains.jet.plugin.util.LongRunningReadTask;
import javax.swing.*;
import java.awt.*;
@@ -54,67 +53,89 @@ import java.util.List;
import java.util.Scanner;
public class BytecodeToolwindow extends JPanel implements Disposable {
private static final int UPDATE_DELAY = 500;
private static final int UPDATE_DELAY = 1000;
private static final String DEFAULT_TEXT = "/*\n" +
"Generated bytecode for Kotlin source file.\n" +
"No Kotlin source file is opened.\n" +
"*/";
private final Editor myEditor;
private final Alarm myUpdateAlarm;
private Location myCurrentLocation;
private final Project myProject;
public BytecodeToolwindow(Project project) {
super(new BorderLayout());
myProject = project;
myEditor =
EditorFactory.getInstance().createEditor(EditorFactory.getInstance().createDocument(""), project, JavaFileType.INSTANCE, true);
add(myEditor.getComponent());
myUpdateAlarm = new Alarm(Alarm.ThreadToUse.SWING_THREAD, this);
myUpdateAlarm.addRequest(new Runnable() {
@Override
public void run() {
myUpdateAlarm.addRequest(this, UPDATE_DELAY);
Location location = Location.fromEditor(FileEditorManager.getInstance(myProject).getSelectedTextEditor());
if (!Comparing.equal(location, myCurrentLocation)) {
updateBytecode(location, myCurrentLocation);
myCurrentLocation = location;
}
public class UpdateBytecodeToolWindowTask extends LongRunningReadTask<Location, String> {
@Override
protected Location prepareRequestInfo() {
Location location = Location.fromEditor(FileEditorManager.getInstance(myProject).getSelectedTextEditor(), myProject);
if (location.getEditor() == null || location.getJetFile() == null) {
return null;
}
}, UPDATE_DELAY);
}
private void updateBytecode(Location location, Location oldLocation) {
Editor editor = location.editor;
return location;
}
if (editor == null) {
@NotNull
@Override
protected Location cloneRequestInfo(@NotNull Location location) {
Location newLocation = super.cloneRequestInfo(location);
assert location.equals(newLocation) : "cloneRequestInfo should generate same location object";
return newLocation;
}
@Override
protected void hideResultOnInvalidLocation() {
setText(DEFAULT_TEXT);
}
else {
VirtualFile vFile = ((EditorEx)editor).getVirtualFile();
if (vFile == null) {
setText(DEFAULT_TEXT);
@NotNull
@Override
protected String processRequest(@NotNull Location location) {
JetFile jetFile = location.getJetFile();
assert jetFile != null;
GenerationState state;
try {
AnalyzeExhaust binding = WholeProjectAnalyzerFacade.analyzeProjectWithCacheOnAFile(jetFile);
if (binding.isError()) {
return printStackTraceToString(binding.getError());
}
state = new GenerationState(jetFile.getProject(), ClassBuilderFactories.TEXT, binding, Collections.singletonList(jetFile));
state.compileCorrectFiles(CompilationErrorHandler.THROW_EXCEPTION);
}
catch (ProcessCanceledException e) {
throw e;
}
catch (Exception e) {
return printStackTraceToString(e);
}
StringBuilder answer = new StringBuilder();
final ClassFileFactory factory = state.getFactory();
for (String filename : factory.files()) {
answer.append("// ================ ");
answer.append(filename);
answer.append(" =================\n");
answer.append(factory.asText(filename)).append("\n\n");
}
return answer.toString();
}
@Override
protected void onResultReady(@NotNull Location requestInfo, final String resultText) {
Editor editor = requestInfo.getEditor();
assert editor != null;
if (resultText == null) {
return;
}
PsiFile psiFile = PsiManager.getInstance(myProject).findFile(vFile);
if (!(psiFile instanceof JetFile)) {
setText(DEFAULT_TEXT);
return;
}
setText(resultText);
if (oldLocation == null ||
!Comparing.equal(oldLocation.editor, location.editor) ||
oldLocation.modificationStamp != location.modificationStamp) {
setText(generateToText((JetFile)psiFile));
}
int fileStartOffset = requestInfo.getStartOffset();
int fileEndOffset = requestInfo.getEndOffset();
Document document = editor.getDocument();
int startLine = document.getLineNumber(location.startOffset);
int endLine = document.getLineNumber(location.endOffset);
if (endLine > startLine && location.endOffset > 0 && document.getCharsSequence().charAt(location.endOffset - 1) == '\n') {
int startLine = document.getLineNumber(fileStartOffset);
int endLine = document.getLineNumber(fileEndOffset);
if (endLine > startLine && fileEndOffset > 0 && document.getCharsSequence().charAt(fileEndOffset - 1) == '\n') {
endLine--;
}
@@ -135,6 +156,37 @@ public class BytecodeToolwindow extends JPanel implements Disposable {
}
}
private final Editor myEditor;
private final Alarm myUpdateAlarm;
private final Project myProject;
private UpdateBytecodeToolWindowTask currentTask = null;
public BytecodeToolwindow(Project project) {
super(new BorderLayout());
myProject = project;
myEditor = EditorFactory.getInstance().createEditor(
EditorFactory.getInstance().createDocument(""), project, JavaFileType.INSTANCE, true);
add(myEditor.getComponent());
myUpdateAlarm = new Alarm(Alarm.ThreadToUse.SWING_THREAD, this);
myUpdateAlarm.addRequest(new Runnable() {
@Override
public void run() {
myUpdateAlarm.addRequest(this, UPDATE_DELAY);
UpdateBytecodeToolWindowTask task = new UpdateBytecodeToolWindowTask();
task.init();
if (task.shouldStart(currentTask)) {
currentTask = task;
currentTask.run();
}
}
}, UPDATE_DELAY);
setText(DEFAULT_TEXT);
}
private static Pair<Integer, Integer> mapLines(String text, int startLine, int endLine) {
int byteCodeLine = 0;
int byteCodeStartLine = -1;
@@ -192,109 +244,29 @@ public class BytecodeToolwindow extends JPanel implements Disposable {
}
}
private void setText(final String text) {
private static String printStackTraceToString(Throwable e) {
StringWriter out = new StringWriter(1024);
PrintWriter printWriter = new PrintWriter(out);
try {
e.printStackTrace(printWriter);
return out.toString().replace("\r", "");
}
finally {
printWriter.close();
}
}
private void setText(@NotNull final String resultText) {
new WriteCommandAction(myProject) {
@Override
protected void run(Result result) throws Throwable {
myEditor.getDocument().setText(text);
myEditor.getDocument().setText(resultText);
}
}.execute();
}
protected String generateToText(JetFile file) {
GenerationState state;
try {
AnalyzeExhaust binding = WholeProjectAnalyzerFacade.analyzeProjectWithCacheOnAFile(file);
// AnalyzingUtils.throwExceptionOnErrors(binding);
if (binding.isError()) {
return printStackTraceToString(binding.getError());
}
state = new GenerationState(file.getProject(), ClassBuilderFactories.TEXT, binding, Collections.singletonList(file));
state.compileCorrectFiles(CompilationErrorHandler.THROW_EXCEPTION);
}
catch (Exception e) {
return printStackTraceToString(e);
}
StringBuilder answer = new StringBuilder();
final ClassFileFactory factory = state.getFactory();
for (String filename : factory.files()) {
answer.append("// ================ ");
answer.append(filename);
answer.append(" =================\n");
answer.append(factory.asText(filename)).append("\n\n");
}
return answer.toString();
}
private static String printStackTraceToString(Throwable e) {StringWriter out = new StringWriter(1024);
e.printStackTrace(new PrintWriter(out));
return out.toString().replace("\r", "");
}
@Override
public void dispose() {
EditorFactory.getInstance().releaseEditor(myEditor);
}
public static class Location {
final Editor editor;
final long modificationStamp;
final int startOffset;
final int endOffset;
private Location(Editor editor) {
this.editor = editor;
modificationStamp = editor != null ? editor.getDocument().getModificationStamp() : 0;
startOffset = editor != null ? editor.getSelectionModel().getSelectionStart() : 0;
endOffset = editor != null ? editor.getSelectionModel().getSelectionEnd() : 0;
}
public static Location fromEditor(Editor editor) {
return new Location(editor);
}
public Editor getEditor() {
return editor;
}
public long getModificationStamp() {
return modificationStamp;
}
public int getStartOffset() {
return startOffset;
}
public int getEndOffset() {
return endOffset;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof Location)) return false;
Location location = (Location)o;
if (endOffset != location.endOffset) return false;
if (modificationStamp != location.modificationStamp) return false;
if (startOffset != location.startOffset) return false;
if (editor != null ? !editor.equals(location.editor) : location.editor != null) return false;
return true;
}
@Override
public int hashCode() {
int result = editor != null ? editor.hashCode() : 0;
result = 31 * result + (int)(modificationStamp ^ (modificationStamp >>> 32));
result = 31 * result + startOffset;
result = 31 * result + endOffset;
return result;
}
}
}
}
@@ -24,17 +24,14 @@ import com.intellij.openapi.application.Result;
import com.intellij.openapi.command.WriteCommandAction;
import com.intellij.openapi.editor.Editor;
import com.intellij.openapi.editor.EditorFactory;
import com.intellij.openapi.editor.ex.EditorEx;
import com.intellij.openapi.fileEditor.FileEditorManager;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.Comparing;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiFile;
import com.intellij.psi.PsiManager;
import com.intellij.psi.util.PsiTreeUtil;
import com.intellij.psi.util.PsiUtilCore;
import com.intellij.util.Alarm;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.jet.lang.descriptors.*;
import org.jetbrains.jet.lang.psi.JetElement;
@@ -47,10 +44,10 @@ import org.jetbrains.jet.lang.resolve.calls.inference.BoundsOwner;
import org.jetbrains.jet.lang.resolve.scopes.receivers.ReceiverDescriptor;
import org.jetbrains.jet.lang.types.JetType;
import org.jetbrains.jet.plugin.JetFileType;
import org.jetbrains.jet.plugin.internal.codewindow.BytecodeToolwindow;
import org.jetbrains.jet.plugin.internal.Location;
import org.jetbrains.jet.plugin.project.WholeProjectAnalyzerFacade;
import org.jetbrains.jet.plugin.util.LongRunningReadTask;
import org.jetbrains.jet.util.slicedmap.ReadOnlySlice;
import org.jetbrains.jet.util.slicedmap.WritableSlice;
import javax.swing.*;
import java.awt.*;
@@ -67,110 +64,121 @@ public class ResolveToolwindow extends JPanel implements Disposable {
public static final String BAR = "\n\n===\n\n";
private static final int UPDATE_DELAY = 500;
private static final int UPDATE_DELAY = 1000;
private static final String DEFAULT_TEXT = "/*\n" +
"Information about symbols resolved by\nKotlin compiler.\n" +
"No Kotlin source file is opened.\n" +
"*/";
private final Editor myEditor;
private final Alarm myUpdateAlarm;
private BytecodeToolwindow.Location myCurrentLocation;
private final Project myProject;
private static final String NO_REFERENCE_TEXT = "/*\n" +
"Information about symbols resolved by\nKotlin compiler.\n" +
"Invalid place for getting reference information.\n" +
"*/";
private class UpdateResolveToolWindowTask extends LongRunningReadTask<Location, String> {
@Override
protected Location prepareRequestInfo() {
Location location = Location.fromEditor(FileEditorManager.getInstance(myProject).getSelectedTextEditor(), myProject);
if (location.getEditor() == null || location.getJetFile() == null) {
return null;
}
return location;
}
@Override
protected void hideResultOnInvalidLocation() {
setText(DEFAULT_TEXT);
}
@NotNull
@Override
protected String processRequest(@NotNull Location requestInfo) {
JetFile jetFile = requestInfo.getJetFile();
assert jetFile != null;
int startOffset = requestInfo.getStartOffset();
int endOffset = requestInfo.getEndOffset();
BindingContext bindingContext = WholeProjectAnalyzerFacade.analyzeProjectWithCacheOnAFile(jetFile).getBindingContext();
PsiElement elementAtOffset;
if (startOffset == endOffset) {
elementAtOffset = PsiUtilCore.getElementAtOffset(jetFile, startOffset);
}
else {
PsiElement start = PsiUtilCore.getElementAtOffset(jetFile, startOffset);
PsiElement end = PsiUtilCore.getElementAtOffset(jetFile, endOffset - 1);
elementAtOffset = PsiTreeUtil.findCommonParent(start, end);
}
PsiElement elementWithDebugInfo = findData(bindingContext, elementAtOffset, RESOLUTION_DEBUG_INFO);
if (elementWithDebugInfo != null) {
return renderDebugInfo(elementWithDebugInfo, bindingContext.get(RESOLUTION_DEBUG_INFO, elementWithDebugInfo), null);
}
@SuppressWarnings("unchecked")
PsiElement elementWithResolvedCall = findData(bindingContext, elementAtOffset, (ReadOnlySlice) RESOLVED_CALL);
if (elementWithResolvedCall instanceof JetElement) {
return renderDebugInfo(elementWithResolvedCall, null,
bindingContext.get(RESOLVED_CALL, (JetElement) elementWithResolvedCall));
}
JetExpression parentExpression = (elementAtOffset instanceof JetExpression) ?
(JetExpression) elementAtOffset :
PsiTreeUtil.getParentOfType(elementAtOffset, JetExpression.class);
if (parentExpression != null) {
JetType type = bindingContext.get(EXPRESSION_TYPE, parentExpression);
String text = parentExpression + "|" + parentExpression.getText() + "| : " + type;
if (parentExpression instanceof JetReferenceExpression) {
JetReferenceExpression referenceExpression = (JetReferenceExpression) parentExpression;
DeclarationDescriptor target = bindingContext.get(REFERENCE_TARGET, referenceExpression);
text += "\nReference target: \n" + target;
}
return text;
}
return NO_REFERENCE_TEXT;
}
@Override
protected void onResultReady(@NotNull Location requestInfo, @Nullable final String resultText) {
if (resultText != null) {
setText(resultText);
}
}
}
private final Alarm myUpdateAlarm;
private final Editor myEditor;
private UpdateResolveToolWindowTask currentTask = null;
private final Project myProject;
public ResolveToolwindow(Project project) {
super(new BorderLayout());
myProject = project;
myEditor = EditorFactory.getInstance().createEditor(EditorFactory.getInstance().createDocument(""), project, JetFileType.INSTANCE, true);
myEditor = EditorFactory.getInstance()
.createEditor(EditorFactory.getInstance().createDocument(""), project, JetFileType.INSTANCE, true);
add(myEditor.getComponent());
myUpdateAlarm = new Alarm(Alarm.ThreadToUse.SWING_THREAD, this);
myUpdateAlarm.addRequest(new Runnable() {
@Override
public void run() {
myUpdateAlarm.addRequest(this, UPDATE_DELAY);
BytecodeToolwindow.Location location = BytecodeToolwindow.Location.fromEditor(FileEditorManager.getInstance(myProject).getSelectedTextEditor());
if (!Comparing.equal(location, myCurrentLocation)) {
render(location, myCurrentLocation);
myCurrentLocation = location;
UpdateResolveToolWindowTask task = new UpdateResolveToolWindowTask();
task.init();
if (task.shouldStart(currentTask)) {
currentTask = task;
currentTask.run();
}
}
}, UPDATE_DELAY);
}
private void render(BytecodeToolwindow.Location location, BytecodeToolwindow.Location oldLocation) {
Editor editor = location.getEditor();
if (editor == null) {
setText(DEFAULT_TEXT);
}
else {
VirtualFile vFile = ((EditorEx) editor).getVirtualFile();
if (vFile == null) {
setText(DEFAULT_TEXT);
return;
}
PsiFile psiFile = PsiManager.getInstance(myProject).findFile(vFile);
if (!(psiFile instanceof JetFile)) {
setText(DEFAULT_TEXT);
return;
}
int startOffset = location.getStartOffset();
int endOffset = location.getEndOffset();
if (oldLocation == null || !Comparing.equal(oldLocation.getEditor(), location.getEditor())
|| oldLocation.getStartOffset() != startOffset
|| oldLocation.getEndOffset() != endOffset) {
BindingContext bindingContext = WholeProjectAnalyzerFacade.analyzeProjectWithCacheOnAFile((JetFile) psiFile)
.getBindingContext();
PsiElement elementAtOffset;
if (startOffset == endOffset) {
elementAtOffset = PsiUtilCore.getElementAtOffset(psiFile, startOffset);
}
else {
PsiElement start = PsiUtilCore.getElementAtOffset(psiFile, startOffset);
PsiElement end = PsiUtilCore.getElementAtOffset(psiFile, endOffset - 1);
elementAtOffset = PsiTreeUtil.findCommonParent(start, end);
}
PsiElement currentElement = elementAtOffset;
boolean callFound = false;
PsiElement elementWithDebugInfo = findData(bindingContext, currentElement, RESOLUTION_DEBUG_INFO);
if (elementWithDebugInfo != null) {
callFound = true;
setText(renderDebugInfo(elementWithDebugInfo, bindingContext.get(RESOLUTION_DEBUG_INFO, elementWithDebugInfo), null));
}
else {
PsiElement elementWithResolvedCall = findData(bindingContext, currentElement, (WritableSlice) RESOLVED_CALL);
if (elementWithResolvedCall instanceof JetElement) {
callFound = true;
setText(renderDebugInfo(elementWithResolvedCall, null, bindingContext.get(RESOLVED_CALL, (JetElement) elementWithResolvedCall)));
}
}
if (!callFound) {
JetExpression parentExpression = (elementAtOffset instanceof JetExpression) ?
(JetExpression) elementAtOffset :
PsiTreeUtil.getParentOfType(elementAtOffset, JetExpression.class);
if (parentExpression != null) {
JetType type = bindingContext.get(EXPRESSION_TYPE, parentExpression);
String text = parentExpression + "|" + parentExpression.getText() + "| : " + type;
if (parentExpression instanceof JetReferenceExpression) {
JetReferenceExpression referenceExpression = (JetReferenceExpression) parentExpression;
DeclarationDescriptor target = bindingContext.get(REFERENCE_TARGET, referenceExpression);
text += "\nReference target: \n" + target;
}
setText(text);
}
}
}
}
setText(DEFAULT_TEXT);
}
@Nullable
@@ -182,18 +190,22 @@ public class ResolveToolwindow extends JPanel implements Disposable {
if (data != null && data != NO_DEBUG_INFO) {
return currentElement;
}
}
currentElement = currentElement.getParent();
}
return null;
}
private static String renderDebugInfo(PsiElement currentElement,
@NotNull
private static String renderDebugInfo(
PsiElement currentElement,
@Nullable ResolutionDebugInfo.Data debugInfo,
@Nullable ResolvedCall<? extends CallableDescriptor> call) {
@Nullable ResolvedCall<? extends CallableDescriptor> call
) {
StringBuilder result = new StringBuilder();
if (debugInfo != null) {
List<? extends ResolutionTask<? extends CallableDescriptor, ?>> resolutionTasks = debugInfo.get(TASKS);
for (ResolutionTask<? extends CallableDescriptor, ?> resolutionTask : resolutionTasks) {
@@ -215,9 +227,11 @@ public class ResolveToolwindow extends JPanel implements Disposable {
return result.toString();
}
private static void renderResolutionLogForCall(Data debugInfo,
private static void renderResolutionLogForCall(
Data debugInfo,
ResolvedCallWithTrace<? extends CallableDescriptor> resolvedCall,
StringBuilder result) {
StringBuilder result
) {
result.append("Trying to call ").append(resolvedCall.getCandidateDescriptor()).append("\n");
StringBuilder errors = debugInfo.getByKey(ERRORS, resolvedCall);
if (errors != null) {
@@ -254,7 +268,6 @@ public class ResolveToolwindow extends JPanel implements Disposable {
}
private static String renderCall(StringBuilder builder, ResolvedCall<? extends CallableDescriptor> resolvedCall) {
CallableDescriptor resultingDescriptor = resolvedCall.getResultingDescriptor();
ReceiverDescriptor receiverArgument = resolvedCall.getReceiverArgument();
ReceiverDescriptor thisObject = resolvedCall.getThisObject();
@@ -329,17 +342,17 @@ public class ResolveToolwindow extends JPanel implements Disposable {
if (receiverArgument.exists()) {
builder.append("/").append(receiverArgument);
}
if (thisObject.exists()) {
builder.append("/this=").append(thisObject);
}
if (thisObject.exists() || receiverArgument.exists()) {
builder.append("/.");
}
}
private void setText(final String text) {
private void setText(@NotNull final String text) {
new WriteCommandAction(myProject) {
@Override
protected void run(Result result) throws Throwable {
@@ -35,7 +35,7 @@ public abstract class LongRunningReadTask<RequestInfo, ResultData> {
INITIALIZED,
STARTED,
FINISHED,
FINISHED_AND_PROCESSED
FINISHED_WITH_ACTUAL_DATA
}
private ProgressIndicator progressIndicator = null;
@@ -45,7 +45,7 @@ public abstract class LongRunningReadTask<RequestInfo, ResultData> {
protected LongRunningReadTask() {}
/** Should be executed in GUI thread */
public boolean isShouldStartWithCancel(@Nullable LongRunningReadTask<RequestInfo, ResultData> previousTask) {
public boolean shouldStart(@Nullable LongRunningReadTask<RequestInfo, ResultData> previousTask) {
ApplicationManager.getApplication().assertIsDispatchThread();
if (currentState != State.INITIALIZED) {
@@ -60,20 +60,19 @@ public abstract class LongRunningReadTask<RequestInfo, ResultData> {
}
if (requestInfo == null) {
if (previousTask != null && (previousTask.currentState == State.FINISHED_AND_PROCESSED || previousTask.currentState == State.FINISHED)) {
if (previousTask != null && (previousTask.currentState == State.FINISHED_WITH_ACTUAL_DATA || previousTask.currentState == State.FINISHED)) {
previousTask.hideResultOnInvalidLocation();
}
return false;
}
if (previousTask != null) {
if (previousTask.currentState == State.STARTED) {
// Start new task only if previous isn't working on similar request
return !requestInfo.equals(previousTask.requestInfo);
}
else if (previousTask.currentState == State.FINISHED_AND_PROCESSED) {
else if (previousTask.currentState == State.FINISHED_WITH_ACTUAL_DATA) {
if (requestInfo.equals(previousTask.requestInfo)) {
return false;
}
@@ -144,7 +143,7 @@ public abstract class LongRunningReadTask<RequestInfo, ResultData> {
if (resultData != null) {
RequestInfo actualInfo = prepareRequestInfo();
if (requestInfo.equals(actualInfo)) {
currentState = State.FINISHED_AND_PROCESSED;
currentState = State.FINISHED_WITH_ACTUAL_DATA;
onResultReady(actualInfo, resultData);
}
}
@@ -172,6 +171,8 @@ public abstract class LongRunningReadTask<RequestInfo, ResultData> {
/**
* Executed in GUI Thread.
*
* @return null if current request is invalid and task shouldn't be executed.
*/
@Nullable
protected abstract RequestInfo prepareRequestInfo();