introduce updateQuickDocAsync()

This commit is contained in:
Gregory.Shrago
2018-08-29 23:04:03 +03:00
parent 5ce8adf088
commit b6a5191c82
@@ -5,10 +5,15 @@ import com.intellij.codeInsight.hint.HintUtil;
import com.intellij.codeInsight.navigation.DocPreviewUtil;
import com.intellij.concurrency.SensitiveProgressWrapper;
import com.intellij.lang.documentation.DocumentationProvider;
import com.intellij.openapi.Disposable;
import com.intellij.openapi.progress.ProcessCanceledException;
import com.intellij.openapi.progress.ProgressIndicator;
import com.intellij.openapi.progress.ProgressManager;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.ui.popup.JBPopup;
import com.intellij.openapi.util.Comparing;
import com.intellij.openapi.util.Disposer;
import com.intellij.openapi.util.Ref;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.openapi.wm.ToolWindow;
import com.intellij.openapi.wm.ToolWindowId;
@@ -17,12 +22,18 @@ import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiQualifiedNamedElement;
import com.intellij.ui.content.Content;
import com.intellij.ui.popup.AbstractPopup;
import com.intellij.util.Consumer;
import com.intellij.util.ObjectUtils;
import com.intellij.util.SingleAlarm;
import com.intellij.util.concurrency.AppExecutorUtil;
import com.intellij.util.ui.UIUtil;
import org.jetbrains.annotations.Contract;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;
import static com.intellij.openapi.progress.util.ProgressIndicatorUtils.runInReadActionWithWriteActionPriority;
@@ -104,4 +115,63 @@ public class QuickDocUtil {
}
return null;
}
public static final Object CUT_AT_CMD = ObjectUtils.sentinel("CUT_AT_CMD");
public static void updateQuickDocAsync(@NotNull PsiElement element,
@NotNull CharSequence prefix,
@NotNull Consumer<Consumer<Object>> provider) {
Project project = element.getProject();
StringBuilder sb = new StringBuilder(prefix);
ConcurrentLinkedQueue<Object> queue = new ConcurrentLinkedQueue<>();
Disposable alarmDisposable = Disposer.newDisposable();
Disposer.register(project, alarmDisposable);
AtomicBoolean stop = new AtomicBoolean(false);
Ref<Object> cutAt = Ref.create(null);
SingleAlarm alarm = new SingleAlarm(() -> {
DocumentationComponent component = getActiveDocComponent(project);
if (component == null) {
stop.set(true);
Disposer.dispose(alarmDisposable);
return;
}
Object s = queue.poll();
while (s != null) {
if (s == CUT_AT_CMD || cutAt.get() == CUT_AT_CMD) {
cutAt.set(s);
s = "";
}
else if (!cutAt.isNull()) {
int idx = StringUtil.indexOf(sb, cutAt.get().toString());
if (idx >= 0) sb.setLength(idx);
cutAt.set(null);
}
sb.append(s);
s = queue.poll();
}
if (stop.get()) {
Disposer.dispose(alarmDisposable);
}
String newText = sb.toString() + "<br><br><br>";
String prevText = component.getText();
if (!Comparing.equal(newText, prevText)) {
component.replaceText(newText, element);
}
}, 100, alarmDisposable);
AppExecutorUtil.getAppExecutorService().submit(() -> {
try {
provider.consume(str -> {
ProgressManager.checkCanceled();
if (stop.get()) throw new ProcessCanceledException();
queue.add(str);
alarm.cancelAndRequest();
});
}
finally {
if (stop.compareAndSet(false, true)) {
alarm.cancelAndRequest();
}
}
});
}
}