mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-18 09:34:34 +07:00
IDEA-154272 Editor opening should do heavy operations in background
This commit is contained in:
@@ -32,6 +32,7 @@ import com.intellij.openapi.editor.Editor;
|
||||
import com.intellij.openapi.fileEditor.FileEditor;
|
||||
import com.intellij.openapi.fileEditor.FileEditorLocation;
|
||||
import com.intellij.openapi.fileEditor.TextEditor;
|
||||
import com.intellij.openapi.fileEditor.impl.text.AsyncEditorLoader;
|
||||
import com.intellij.openapi.keymap.KeymapUtil;
|
||||
import com.intellij.openapi.preview.PreviewManager;
|
||||
import com.intellij.openapi.progress.ProgressIndicator;
|
||||
@@ -1067,13 +1068,20 @@ public class ShowUsagesAction extends AnAction implements PopupAction {
|
||||
int maxUsages,
|
||||
@NotNull FindUsagesOptions options,
|
||||
boolean isWarning) {
|
||||
JComponent label = createHintComponent(hint, handler, popupPosition, editor, ShowUsagesAction::hideHints, maxUsages, options, isWarning);
|
||||
if (editor == null || editor.isDisposed() || !editor.getComponent().isShowing()) {
|
||||
HintManager.getInstance().showHint(label, popupPosition, HintManager.HIDE_BY_ANY_KEY |
|
||||
HintManager.HIDE_BY_TEXT_CHANGE | HintManager.HIDE_BY_SCROLLING, 0);
|
||||
}
|
||||
else {
|
||||
HintManager.getInstance().showInformationHint(editor, label);
|
||||
Runnable runnable = () -> {
|
||||
JComponent label = createHintComponent(hint, handler, popupPosition, editor, ShowUsagesAction::hideHints, maxUsages, options, isWarning);
|
||||
if (editor == null || editor.isDisposed() || !editor.getComponent().isShowing()) {
|
||||
HintManager.getInstance().showHint(label, popupPosition, HintManager.HIDE_BY_ANY_KEY |
|
||||
HintManager.HIDE_BY_TEXT_CHANGE | HintManager.HIDE_BY_SCROLLING, 0);
|
||||
}
|
||||
else {
|
||||
HintManager.getInstance().showInformationHint(editor, label);
|
||||
}
|
||||
};
|
||||
if (editor == null) {
|
||||
runnable.run();
|
||||
} else {
|
||||
AsyncEditorLoader.performWhenLoaded(editor, runnable);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+31
@@ -20,15 +20,21 @@
|
||||
package com.intellij.openapi.fileEditor.impl.text;
|
||||
|
||||
import com.intellij.codeHighlighting.BackgroundEditorHighlighter;
|
||||
import com.intellij.codeInsight.daemon.DaemonCodeAnalyzer;
|
||||
import com.intellij.codeInsight.daemon.impl.TextEditorBackgroundHighlighter;
|
||||
import com.intellij.codeInsight.folding.CodeFoldingManager;
|
||||
import com.intellij.codeInsight.lookup.LookupManager;
|
||||
import com.intellij.codeInsight.lookup.impl.LookupImpl;
|
||||
import com.intellij.openapi.actionSystem.LangDataKeys;
|
||||
import com.intellij.openapi.actionSystem.PlatformDataKeys;
|
||||
import com.intellij.openapi.editor.Document;
|
||||
import com.intellij.openapi.fileEditor.FileDocumentManager;
|
||||
import com.intellij.openapi.module.ModuleUtilCore;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.vfs.VirtualFile;
|
||||
import com.intellij.psi.PsiFile;
|
||||
import com.intellij.psi.PsiManager;
|
||||
import com.intellij.ui.EditorNotifications;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
public class PsiAwareTextEditorImpl extends TextEditorImpl {
|
||||
@@ -38,6 +44,27 @@ public class PsiAwareTextEditorImpl extends TextEditorImpl {
|
||||
super(project, file, provider);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
protected Runnable loadEditorInBackground() {
|
||||
Runnable baseAction = super.loadEditorInBackground();
|
||||
PsiFile psiFile = PsiManager.getInstance(myProject).findFile(myFile);
|
||||
Document document = FileDocumentManager.getInstance().getDocument(myFile);
|
||||
CodeFoldingState foldingState = document != null && !myProject.isDefault()
|
||||
? CodeFoldingManager.getInstance(myProject).buildInitialFoldings(document)
|
||||
: null;
|
||||
return () -> {
|
||||
baseAction.run();
|
||||
if (foldingState != null) {
|
||||
foldingState.setToEditor(getEditor());
|
||||
}
|
||||
if (psiFile != null) {
|
||||
DaemonCodeAnalyzer.getInstance(myProject).restart(psiFile);
|
||||
}
|
||||
EditorNotifications.getInstance(myProject).updateNotifications(myFile);
|
||||
};
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
protected TextEditorComponent createEditorComponent(final Project project, final VirtualFile file) {
|
||||
@@ -46,6 +73,10 @@ public class PsiAwareTextEditorImpl extends TextEditorImpl {
|
||||
|
||||
@Override
|
||||
public BackgroundEditorHighlighter getBackgroundHighlighter() {
|
||||
if (!AsyncEditorLoader.isEditorLoaded(getEditor())) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (myBackgroundHighlighter == null) {
|
||||
myBackgroundHighlighter = new TextEditorBackgroundHighlighter(myProject, getEditor());
|
||||
}
|
||||
|
||||
+3
-38
@@ -26,7 +26,6 @@ import com.intellij.openapi.diagnostic.Logger;
|
||||
import com.intellij.openapi.editor.Document;
|
||||
import com.intellij.openapi.editor.Editor;
|
||||
import com.intellij.openapi.fileEditor.*;
|
||||
import com.intellij.openapi.progress.ProcessCanceledException;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.util.WriteExternalException;
|
||||
import com.intellij.openapi.util.registry.Registry;
|
||||
@@ -37,7 +36,7 @@ import org.jdom.Element;
|
||||
import org.jetbrains.annotations.NonNls;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
public class PsiAwareTextEditorProvider extends TextEditorProvider implements AsyncFileEditorProvider {
|
||||
public class PsiAwareTextEditorProvider extends TextEditorProvider {
|
||||
private static final Logger LOG = Logger.getInstance("#com.intellij.openapi.fileEditor.impl.text.PsiAwareTextEditorProvider");
|
||||
@NonNls
|
||||
private static final String FOLDING_ELEMENT = "folding";
|
||||
@@ -45,41 +44,7 @@ public class PsiAwareTextEditorProvider extends TextEditorProvider implements As
|
||||
@Override
|
||||
@NotNull
|
||||
public FileEditor createEditor(@NotNull final Project project, @NotNull final VirtualFile file) {
|
||||
return createEditorAsync(project, file).build();
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public Builder createEditorAsync(@NotNull final Project project, @NotNull final VirtualFile file) {
|
||||
if (!accept(project, file)) {
|
||||
LOG.error("Cannot open text editor for " + file);
|
||||
}
|
||||
CodeFoldingState state = null;
|
||||
if (!project.isDefault()) { // There's no CodeFoldingManager for default project (which is used in diff command-line application)
|
||||
try {
|
||||
Document document = FileDocumentManager.getInstance().getDocument(file);
|
||||
if (document != null) {
|
||||
state = CodeFoldingManager.getInstance(project).buildInitialFoldings(document);
|
||||
}
|
||||
}
|
||||
catch (ProcessCanceledException e) {
|
||||
throw e;
|
||||
}
|
||||
catch (Exception e) {
|
||||
LOG.error("Error building initial foldings", e);
|
||||
}
|
||||
}
|
||||
final CodeFoldingState finalState = state;
|
||||
return new Builder() {
|
||||
@Override
|
||||
public FileEditor build() {
|
||||
final PsiAwareTextEditorImpl editor = new PsiAwareTextEditorImpl(project, file, PsiAwareTextEditorProvider.this);
|
||||
if (finalState != null) {
|
||||
finalState.setToEditor(editor.getEditor());
|
||||
}
|
||||
return editor;
|
||||
}
|
||||
};
|
||||
return new PsiAwareTextEditorImpl(project, file, this);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -149,7 +114,7 @@ public class PsiAwareTextEditorProvider extends TextEditorProvider implements As
|
||||
super.setStateImpl(project, editor, state);
|
||||
// Folding
|
||||
final CodeFoldingState foldState = state.getFoldingState();
|
||||
if (project != null && foldState != null) {
|
||||
if (project != null && foldState != null && AsyncEditorLoader.isEditorLoaded(editor)) {
|
||||
if (!PsiDocumentManager.getInstance(project).isCommitted(editor.getDocument())) {
|
||||
PsiDocumentManager.getInstance(project).commitDocument(editor.getDocument());
|
||||
LOG.error("File should be parsed when changing editor state, otherwise UI might be frozen for a considerable time");
|
||||
|
||||
@@ -37,6 +37,7 @@ import com.intellij.openapi.editor.event.VisibleAreaEvent;
|
||||
import com.intellij.openapi.editor.event.VisibleAreaListener;
|
||||
import com.intellij.openapi.editor.ex.ScrollingModelEx;
|
||||
import com.intellij.openapi.editor.ex.util.EditorUtil;
|
||||
import com.intellij.openapi.fileEditor.impl.text.AsyncEditorLoader;
|
||||
import com.intellij.openapi.util.Disposer;
|
||||
import com.intellij.util.containers.ContainerUtil;
|
||||
import com.intellij.util.ui.Animator;
|
||||
@@ -141,8 +142,7 @@ public class ScrollingModelImpl implements ScrollingModelEx {
|
||||
assertIsDispatchThread();
|
||||
myEditor.validateSize();
|
||||
if (myEditor.myUseNewRendering) {
|
||||
VisualPosition caretPosition = myEditor.getCaretModel().getVisualPosition();
|
||||
scrollTo(caretPosition, scrollType);
|
||||
AsyncEditorLoader.performWhenLoaded(myEditor, () -> scrollTo(myEditor.getCaretModel().getVisualPosition(), scrollType));
|
||||
}
|
||||
else {
|
||||
LogicalPosition caretPosition = myEditor.getCaretModel().getLogicalPosition();
|
||||
@@ -166,8 +166,7 @@ public class ScrollingModelImpl implements ScrollingModelEx {
|
||||
public void scrollTo(@NotNull LogicalPosition pos, @NotNull ScrollType scrollType) {
|
||||
assertIsDispatchThread();
|
||||
|
||||
Point targetLocation = myEditor.logicalPositionToXY(pos);
|
||||
scrollTo(targetLocation, scrollType);
|
||||
AsyncEditorLoader.performWhenLoaded(myEditor, () -> scrollTo(myEditor.logicalPositionToXY(pos), scrollType));
|
||||
}
|
||||
|
||||
private static void assertIsDispatchThread() {
|
||||
|
||||
@@ -32,6 +32,7 @@ import com.intellij.openapi.editor.ex.DocumentEx;
|
||||
import com.intellij.openapi.editor.ex.EditorEx;
|
||||
import com.intellij.openapi.editor.ex.EditorSettingsExternalizable;
|
||||
import com.intellij.openapi.editor.impl.softwrap.SoftWrapAppliancePlaces;
|
||||
import com.intellij.openapi.fileEditor.impl.text.AsyncEditorLoader;
|
||||
import com.intellij.openapi.fileTypes.FileType;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.util.registry.Registry;
|
||||
@@ -336,7 +337,7 @@ public class SettingsImpl implements EditorSettings {
|
||||
}
|
||||
|
||||
private void reinitDocumentIndentOptions() {
|
||||
if (myEditor == null || myEditor.isViewer()) return;
|
||||
if (myEditor == null || myEditor.isViewer() || AsyncEditorLoader.isCreatingAsyncEditor()) return;
|
||||
final Project project = myEditor.getProject();
|
||||
final DocumentEx document = myEditor.getDocument();
|
||||
|
||||
@@ -363,7 +364,7 @@ public class SettingsImpl implements EditorSettings {
|
||||
if (myTabSize != null) return myTabSize.intValue();
|
||||
if (myCachedTabSize != null) return myCachedTabSize.intValue();
|
||||
int tabSize;
|
||||
if (project == null || project.isDisposed()) {
|
||||
if (project == null || project.isDisposed() || AsyncEditorLoader.isCreatingAsyncEditor()) {
|
||||
tabSize = CodeStyleSettingsManager.getSettings(null).getTabSize(null);
|
||||
}
|
||||
else {
|
||||
|
||||
+5
-1
@@ -73,6 +73,7 @@ import com.intellij.ui.tabs.impl.JBTabsImpl;
|
||||
import com.intellij.util.SmartList;
|
||||
import com.intellij.util.concurrency.Semaphore;
|
||||
import com.intellij.util.containers.ContainerUtil;
|
||||
import com.intellij.util.io.storage.HeavyProcessLatch;
|
||||
import com.intellij.util.messages.MessageBusConnection;
|
||||
import com.intellij.util.messages.impl.MessageListenerList;
|
||||
import com.intellij.util.ui.JBUI;
|
||||
@@ -854,6 +855,9 @@ public class FileEditorManagerImpl extends FileEditorManagerEx implements Persis
|
||||
if (myProject.isDisposed() || !file.isValid()) {
|
||||
return;
|
||||
}
|
||||
|
||||
HeavyProcessLatch.INSTANCE.prioritizeUiActivity();
|
||||
|
||||
compositeRef.set(window.findFileComposite(file));
|
||||
boolean newEditor = compositeRef.isNull();
|
||||
if (newEditor) {
|
||||
@@ -964,7 +968,7 @@ public class FileEditorManagerImpl extends FileEditorManagerEx implements Persis
|
||||
}
|
||||
};
|
||||
|
||||
commitAndInvoke(runnable);
|
||||
UIUtil.invokeAndWaitIfNeeded(runnable);
|
||||
|
||||
EditorWithProviderComposite composite = compositeRef.get();
|
||||
return Pair.create(composite == null ? EMPTY_EDITOR_ARRAY : composite.getEditors(),
|
||||
|
||||
+220
@@ -0,0 +1,220 @@
|
||||
/*
|
||||
* Copyright 2000-2016 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 com.intellij.openapi.fileEditor.impl.text;
|
||||
|
||||
import com.intellij.openapi.application.ApplicationManager;
|
||||
import com.intellij.openapi.editor.Editor;
|
||||
import com.intellij.openapi.fileEditor.*;
|
||||
import com.intellij.openapi.progress.ProcessCanceledException;
|
||||
import com.intellij.openapi.progress.ProgressIndicator;
|
||||
import com.intellij.openapi.progress.util.ProgressIndicatorBase;
|
||||
import com.intellij.openapi.progress.util.ProgressIndicatorUtils;
|
||||
import com.intellij.openapi.progress.util.ReadTask;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.util.Computable;
|
||||
import com.intellij.openapi.util.Disposer;
|
||||
import com.intellij.openapi.util.Key;
|
||||
import com.intellij.openapi.util.Ref;
|
||||
import com.intellij.openapi.wm.IdeFocusManager;
|
||||
import com.intellij.psi.PsiDocumentManager;
|
||||
import com.intellij.util.ObjectUtils;
|
||||
import com.intellij.util.concurrency.AppExecutorUtil;
|
||||
import com.intellij.util.concurrency.Semaphore;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
|
||||
public class AsyncEditorLoader {
|
||||
private static final ExecutorService ourExecutor = AppExecutorUtil.createBoundedApplicationPoolExecutor(2);
|
||||
private static final Key<AsyncEditorLoader> ASYNC_LOADER = Key.create("ASYNC_LOADER");
|
||||
private static boolean ourCreatingAsyncEditor;
|
||||
@NotNull private final Editor myEditor;
|
||||
@NotNull private final Project myProject;
|
||||
@NotNull private final TextEditorImpl myTextEditor;
|
||||
@NotNull private final TextEditorComponent myEditorComponent;
|
||||
@NotNull private final TextEditorProvider myProvider;
|
||||
private boolean myLoaded;
|
||||
private final List<Runnable> myDelayedActions = new ArrayList<>();
|
||||
private TextEditorState myDelayedState;
|
||||
|
||||
AsyncEditorLoader(@NotNull TextEditorImpl textEditor, @NotNull TextEditorComponent component, @NotNull TextEditorProvider provider) {
|
||||
myProvider = provider;
|
||||
myTextEditor = textEditor;
|
||||
myProject = textEditor.myProject;
|
||||
myEditorComponent = component;
|
||||
|
||||
myEditor = textEditor.getEditor();
|
||||
myEditor.putUserData(ASYNC_LOADER, this);
|
||||
|
||||
myEditorComponent.getContentPanel().setVisible(false);
|
||||
}
|
||||
|
||||
void scheduleBackgroundLoading(boolean firstTime) {
|
||||
ReadTask task = new ReadTask() {
|
||||
PsiDocumentManager pdm = PsiDocumentManager.getInstance(myProject);
|
||||
long startStamp = myEditor.getDocument().getModificationStamp();
|
||||
|
||||
@Override
|
||||
public Continuation runBackgroundProcess(@NotNull ProgressIndicator indicator) throws ProcessCanceledException {
|
||||
return pdm.commitAndRunReadAction(() -> {
|
||||
if (Disposer.isDisposed(myTextEditor)) return null;
|
||||
|
||||
Runnable applyResults = myTextEditor.loadEditorInBackground();
|
||||
return new Continuation(() -> {
|
||||
if (Disposer.isDisposed(myTextEditor)) return;
|
||||
|
||||
if (startStamp != myEditor.getDocument().getModificationStamp()) {
|
||||
onCanceled(indicator);
|
||||
return;
|
||||
}
|
||||
|
||||
applyResults.run();
|
||||
loadingFinished();
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCanceled(@NotNull ProgressIndicator indicator) {
|
||||
scheduleBackgroundLoading(false);
|
||||
}
|
||||
};
|
||||
|
||||
if (!firstTime || !loadImmediately(task)) {
|
||||
myEditorComponent.startLoading();
|
||||
ProgressIndicatorUtils.scheduleWithWriteActionPriority(ourExecutor, task);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Possible alternatives:
|
||||
* 1. show "Loading" from the beginning, then it'll be always noticeable at least in fade-out phase
|
||||
* 2. show a gray screen for some time and then "Loading" if it's still loading; it'll produce quick background blinking for all editors
|
||||
* 3. show non-highlighted and unfolded editor as "Loading" background and allow it to relayout at the end of loading phase
|
||||
* 4. freeze EDT a bit and hope that for small editors it'll suffice and for big ones show "Loading" after that.
|
||||
* This strategy seems to produce minimal blinking annoyance.
|
||||
*/
|
||||
private boolean loadImmediately(ReadTask task) {
|
||||
if (PsiDocumentManager.getInstance(myProject).hasUncommitedDocuments() ||
|
||||
ApplicationManager.getApplication().isWriteAccessAllowed()) {
|
||||
return false; // cannot perform commitAndRunReadAction in parallel to EDT waiting
|
||||
}
|
||||
|
||||
Semaphore semaphore = new Semaphore();
|
||||
semaphore.down();
|
||||
Ref<ReadTask.Continuation> continuationRef = Ref.create();
|
||||
ProgressIndicatorBase indicator = new ProgressIndicatorBase();
|
||||
ourExecutor.submit(() -> {
|
||||
try {
|
||||
ProgressIndicatorUtils.runWithWriteActionPriority(() -> continuationRef.set(task.runBackgroundProcess(indicator)),
|
||||
indicator);
|
||||
}
|
||||
finally {
|
||||
semaphore.up();
|
||||
}
|
||||
});
|
||||
ReadTask.Continuation applyImmediately = semaphore.waitFor(200) ? continuationRef.get() : null;
|
||||
if (applyImmediately != null) {
|
||||
applyImmediately.getAction().run();
|
||||
return true;
|
||||
}
|
||||
|
||||
indicator.cancel();
|
||||
return false;
|
||||
}
|
||||
|
||||
private void loadingFinished() {
|
||||
myLoaded = true;
|
||||
myEditor.putUserData(ASYNC_LOADER, null);
|
||||
myEditorComponent.stopLoading();
|
||||
myEditorComponent.getContentPanel().setVisible(true);
|
||||
|
||||
if (myDelayedState != null) {
|
||||
TextEditorState state = new TextEditorState();
|
||||
state.setFoldingState(myDelayedState.getFoldingState());
|
||||
myProvider.setStateImpl(myProject, myEditor, state);
|
||||
myDelayedState = null;
|
||||
}
|
||||
|
||||
for (Runnable runnable : ObjectUtils.assertNotNull(myDelayedActions)) {
|
||||
myEditor.getScrollingModel().disableAnimation();
|
||||
runnable.run();
|
||||
}
|
||||
myEditor.getScrollingModel().enableAnimation();
|
||||
|
||||
if (FileEditorManager.getInstance(myProject).getSelectedTextEditor() == myEditor) {
|
||||
IdeFocusManager.getInstance(myProject).requestFocus(myTextEditor.getPreferredFocusedComponent(), true);
|
||||
}
|
||||
}
|
||||
|
||||
public static void performWhenLoaded(@NotNull Editor editor, @NotNull Runnable runnable) {
|
||||
ApplicationManager.getApplication().assertIsDispatchThread();
|
||||
AsyncEditorLoader loader = editor.getUserData(ASYNC_LOADER);
|
||||
if (loader == null) {
|
||||
runnable.run();
|
||||
} else {
|
||||
loader.myDelayedActions.add(runnable);
|
||||
}
|
||||
}
|
||||
|
||||
@NotNull
|
||||
TextEditorState getEditorState(@NotNull FileEditorStateLevel level) {
|
||||
ApplicationManager.getApplication().assertIsDispatchThread();
|
||||
|
||||
|
||||
TextEditorState state = myProvider.getStateImpl(myProject, myEditor, level);
|
||||
if (!myLoaded && myDelayedState != null) {
|
||||
state.setDelayedFoldState(myDelayedState::getFoldingState);
|
||||
}
|
||||
return state;
|
||||
}
|
||||
|
||||
void setEditorState(@NotNull final TextEditorState state) {
|
||||
ApplicationManager.getApplication().assertIsDispatchThread();
|
||||
|
||||
if (!myLoaded) {
|
||||
myDelayedState = state;
|
||||
}
|
||||
|
||||
myProvider.setStateImpl(myProject, myEditor, state);
|
||||
}
|
||||
|
||||
public static boolean isEditorLoaded(@NotNull Editor editor) {
|
||||
return editor.getUserData(ASYNC_LOADER) == null;
|
||||
}
|
||||
|
||||
//todo remove this with async indent inference
|
||||
public static boolean isCreatingAsyncEditor() {
|
||||
ApplicationManager.getApplication().assertIsDispatchThread();
|
||||
return ourCreatingAsyncEditor;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
static TextEditorComponent createAsyncEditor(@NotNull Computable<TextEditorComponent> computable) {
|
||||
ApplicationManager.getApplication().assertIsDispatchThread();
|
||||
assert !ourCreatingAsyncEditor;
|
||||
ourCreatingAsyncEditor = true;
|
||||
try {
|
||||
return computable.compute();
|
||||
}
|
||||
finally {
|
||||
ourCreatingAsyncEditor = false;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
-3
@@ -23,7 +23,6 @@ import com.intellij.openapi.diagnostic.Logger;
|
||||
import com.intellij.openapi.editor.Document;
|
||||
import com.intellij.openapi.editor.Editor;
|
||||
import com.intellij.openapi.editor.EditorFactory;
|
||||
import com.intellij.openapi.editor.colors.EditorColorsManager;
|
||||
import com.intellij.openapi.editor.event.DocumentAdapter;
|
||||
import com.intellij.openapi.editor.event.DocumentEvent;
|
||||
import com.intellij.openapi.editor.ex.EditorEx;
|
||||
@@ -166,8 +165,6 @@ class TextEditorComponent extends JBLoadingPanel implements DataProvider {
|
||||
((EditorMarkupModel) editor.getMarkupModel()).setErrorStripeVisible(true);
|
||||
((EditorEx) editor).getGutterComponentEx().setForceShowRightFreePaintersArea(true);
|
||||
|
||||
EditorHighlighter highlighter = EditorHighlighterFactory.getInstance().createEditorHighlighter(myFile, EditorColorsManager.getInstance().getGlobalScheme(), myProject);
|
||||
((EditorEx) editor).setHighlighter(highlighter);
|
||||
((EditorEx) editor).setFile(myFile);
|
||||
|
||||
((EditorEx)editor).setContextMenuGroupId(IdeActions.GROUP_EDITOR_POPUP);
|
||||
|
||||
+24
-6
@@ -19,6 +19,11 @@ import com.intellij.codeHighlighting.BackgroundEditorHighlighter;
|
||||
import com.intellij.ide.structureView.StructureViewBuilder;
|
||||
import com.intellij.openapi.editor.Document;
|
||||
import com.intellij.openapi.editor.Editor;
|
||||
import com.intellij.openapi.editor.colors.EditorColorsManager;
|
||||
import com.intellij.openapi.editor.colors.EditorColorsScheme;
|
||||
import com.intellij.openapi.editor.ex.EditorEx;
|
||||
import com.intellij.openapi.editor.highlighter.EditorHighlighter;
|
||||
import com.intellij.openapi.editor.highlighter.EditorHighlighterFactory;
|
||||
import com.intellij.openapi.fileEditor.*;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.util.UserDataHolderBase;
|
||||
@@ -37,13 +42,25 @@ public class TextEditorImpl extends UserDataHolderBase implements TextEditor {
|
||||
protected final Project myProject;
|
||||
private final PropertyChangeSupport myChangeSupport;
|
||||
@NotNull private final TextEditorComponent myComponent;
|
||||
private final TextEditorProvider myProvider;
|
||||
@NotNull protected final VirtualFile myFile;
|
||||
private final AsyncEditorLoader myAsyncLoader;
|
||||
|
||||
TextEditorImpl(@NotNull final Project project, @NotNull final VirtualFile file, final TextEditorProvider provider) {
|
||||
myProject = project;
|
||||
myProvider = provider;
|
||||
myFile = file;
|
||||
myChangeSupport = new PropertyChangeSupport(this);
|
||||
myComponent = createEditorComponent(project, file);
|
||||
myComponent = AsyncEditorLoader.createAsyncEditor(() -> createEditorComponent(project, file));
|
||||
myAsyncLoader = new AsyncEditorLoader(this, myComponent, provider);
|
||||
myAsyncLoader.scheduleBackgroundLoading(true);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
protected Runnable loadEditorInBackground() {
|
||||
EditorColorsScheme scheme = EditorColorsManager.getInstance().getGlobalScheme();
|
||||
EditorHighlighter highlighter = EditorHighlighterFactory.getInstance().createEditorHighlighter(myFile, scheme, myProject);
|
||||
EditorEx editor = (EditorEx)getEditor();
|
||||
highlighter.setText(editor.getDocument().getImmutableCharSequence());
|
||||
return () -> editor.setHighlighter(highlighter);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@@ -63,6 +80,7 @@ public class TextEditorImpl extends UserDataHolderBase implements TextEditor {
|
||||
}
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
public JComponent getPreferredFocusedComponent(){
|
||||
return getActiveEditor().getContentComponent();
|
||||
}
|
||||
@@ -90,12 +108,12 @@ public class TextEditorImpl extends UserDataHolderBase implements TextEditor {
|
||||
@Override
|
||||
@NotNull
|
||||
public FileEditorState getState(@NotNull FileEditorStateLevel level) {
|
||||
return myProvider.getStateImpl(myProject, getActiveEditor(), level);
|
||||
return myAsyncLoader.getEditorState(level);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setState(@NotNull final FileEditorState state) {
|
||||
myProvider.setStateImpl(myProject, getActiveEditor(), (TextEditorState)state);
|
||||
myAsyncLoader.setEditorState((TextEditorState)state);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -166,6 +184,6 @@ public class TextEditorImpl extends UserDataHolderBase implements TextEditor {
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "Editor: "+getComponent().getFile();
|
||||
return "Editor: "+myComponent.getFile();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,10 +18,8 @@ package com.intellij.ui;
|
||||
import com.intellij.openapi.application.ApplicationManager;
|
||||
import com.intellij.openapi.application.ModalityState;
|
||||
import com.intellij.openapi.extensions.ExtensionPointName;
|
||||
import com.intellij.openapi.fileEditor.FileEditor;
|
||||
import com.intellij.openapi.fileEditor.FileEditorManager;
|
||||
import com.intellij.openapi.fileEditor.FileEditorManagerAdapter;
|
||||
import com.intellij.openapi.fileEditor.FileEditorManagerListener;
|
||||
import com.intellij.openapi.fileEditor.*;
|
||||
import com.intellij.openapi.fileEditor.impl.text.AsyncEditorLoader;
|
||||
import com.intellij.openapi.progress.ProcessCanceledException;
|
||||
import com.intellij.openapi.progress.ProgressIndicator;
|
||||
import com.intellij.openapi.progress.util.ProgressIndicatorBase;
|
||||
@@ -111,8 +109,10 @@ public class EditorNotificationsImpl extends EditorNotifications {
|
||||
|
||||
@Nullable
|
||||
private ReadTask createTask(@NotNull final ProgressIndicator indicator, @NotNull final VirtualFile file) {
|
||||
final FileEditor[] editors = FileEditorManager.getInstance(myProject).getAllEditors(file);
|
||||
if (editors.length == 0) return null;
|
||||
List<FileEditor> editors = ContainerUtil.filter(
|
||||
FileEditorManager.getInstance(myProject).getAllEditors(file),
|
||||
editor -> !(editor instanceof TextEditor) || AsyncEditorLoader.isEditorLoaded(((TextEditor) editor).getEditor()));
|
||||
if (editors.isEmpty()) return null;
|
||||
|
||||
return new ReadTask() {
|
||||
private boolean isOutdated() {
|
||||
|
||||
Reference in New Issue
Block a user