Merge branch 'vshatrov/webconsole'

This commit is contained in:
Viktor Shatrov
2018-12-17 23:13:21 +03:00
3 changed files with 260 additions and 137 deletions
@@ -0,0 +1,215 @@
// Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
package com.intellij.execution.console;
import com.intellij.execution.ui.ConsoleViewContentType;
import com.intellij.ide.GeneralSettings;
import com.intellij.openapi.Disposable;
import com.intellij.openapi.actionSystem.EmptyAction;
import com.intellij.openapi.actionSystem.IdeActions;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.application.TransactionGuard;
import com.intellij.openapi.editor.Document;
import com.intellij.openapi.editor.Editor;
import com.intellij.openapi.editor.EditorFactory;
import com.intellij.openapi.editor.ex.EditorEx;
import com.intellij.openapi.editor.ex.FocusChangeListener;
import com.intellij.openapi.editor.highlighter.EditorHighlighterFactory;
import com.intellij.openapi.fileEditor.*;
import com.intellij.openapi.fileEditor.impl.FileEditorManagerImpl;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.Comparing;
import com.intellij.openapi.util.Disposer;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.util.DocumentUtil;
import com.intellij.util.ObjectUtils;
import com.intellij.util.messages.MessageBusConnection;
import com.intellij.util.ui.UIUtil;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import javax.swing.*;
public class ConsoleExecutionEditor implements Disposable {
private final EditorEx myConsoleEditor;
private EditorEx myCurrentEditor;
private final Document myEditorDocument;
private final LanguageConsoleImpl.Helper myHelper;
private final MessageBusConnection myBusConnection;
@Nullable
private String myPrompt = "> ";
@NotNull
private ConsoleViewContentType myPromptAttributes = ConsoleViewContentType.USER_INPUT;
public ConsoleExecutionEditor(@NotNull LanguageConsoleImpl.Helper helper) {
myHelper = helper;
EditorFactory editorFactory = EditorFactory.getInstance();
myEditorDocument = helper.getDocument();
myConsoleEditor = (EditorEx)editorFactory.createEditor(myEditorDocument, helper.project);
myConsoleEditor.getScrollPane().getHorizontalScrollBar().setEnabled(false);
myConsoleEditor.addFocusListener(myFocusListener);
myConsoleEditor.getSettings().setVirtualSpace(false);
myCurrentEditor = myConsoleEditor;
myBusConnection = getProject().getMessageBus().connect();
// action shortcuts are not yet registered
ApplicationManager.getApplication().invokeLater(() -> installEditorFactoryListener(), getProject().getDisposed());
}
private final FocusChangeListener myFocusListener = new FocusChangeListener() {
@Override
public void focusGained(@NotNull Editor editor) {
myCurrentEditor = (EditorEx)editor;
if (GeneralSettings.getInstance().isSaveOnFrameDeactivation()) {
TransactionGuard.submitTransaction(ConsoleExecutionEditor.this, () -> FileDocumentManager.getInstance().saveAllDocuments()); // PY-12487
}
}
@Override
public void focusLost(@NotNull Editor editor) {
}
};
public void initComponent() {
myConsoleEditor.setContextMenuGroupId(IdeActions.GROUP_CONSOLE_EDITOR_POPUP);
myConsoleEditor.setHighlighter(
EditorHighlighterFactory.getInstance().createEditorHighlighter(getVirtualFile(), myConsoleEditor.getColorsScheme(), getProject()));
setPromptInner(myPrompt);
}
@NotNull
public final VirtualFile getVirtualFile() {
return myHelper.virtualFile;
}
public EditorEx getEditor() {
return myConsoleEditor;
}
@NotNull
public EditorEx getCurrentEditor() {
return ObjectUtils.notNull(myCurrentEditor, myConsoleEditor);
}
public Document getDocument() {
return myEditorDocument;
}
public JComponent getComponent() {
return myConsoleEditor.getComponent();
}
public void setConsoleEditorEnabled(boolean consoleEditorEnabled) {
if (isConsoleEditorEnabled() == consoleEditorEnabled) {
return;
}
if (consoleEditorEnabled) {
FileEditorManager.getInstance(getProject()).closeFile(getVirtualFile());
myCurrentEditor = myConsoleEditor;
}
myConsoleEditor.getComponent().setVisible(consoleEditorEnabled);
}
private Project getProject() {
return myHelper.project;
}
public final boolean isConsoleEditorEnabled() {
return myConsoleEditor.getComponent().isVisible();
}
@Nullable
public String getPrompt() {
return myPrompt;
}
@NotNull
public ConsoleViewContentType getPromptAttributes() {
return myPromptAttributes;
}
public void setPromptAttributes(@NotNull ConsoleViewContentType textAttributes) {
myPromptAttributes = textAttributes;
}
public void setPrompt(@Nullable String prompt) {
// always add space to the prompt otherwise it may look ugly
myPrompt = prompt != null && !prompt.endsWith(" ") ? prompt + " " : prompt;
setPromptInner(myPrompt);
}
public void setEditable(boolean editable) {
myConsoleEditor.setRendererMode(!editable);
setPromptInner(editable ? myPrompt : "");
}
public boolean isEditable() {
return !myConsoleEditor.isRendererMode();
}
private void setPromptInner(@Nullable final String prompt) {
UIUtil.invokeAndWaitIfNeeded((Runnable)() -> {
if (!myConsoleEditor.isDisposed()) {
myConsoleEditor.setPrefixTextAndAttributes(prompt, myPromptAttributes.getAttributes());
}
});
}
private void installEditorFactoryListener() {
FileEditorManagerListener fileEditorListener = new FileEditorManagerListener() {
@Override
public void fileOpened(@NotNull FileEditorManager source, @NotNull VirtualFile file) {
if (myConsoleEditor == null || !Comparing.equal(file, getVirtualFile())) {
return;
}
Editor selectedTextEditor = source.getSelectedTextEditor();
for (FileEditor fileEditor : source.getAllEditors(file)) {
if (!(fileEditor instanceof TextEditor)) {
continue;
}
final EditorEx editor = (EditorEx)((TextEditor)fileEditor).getEditor();
editor.addFocusListener(myFocusListener);
if (selectedTextEditor == editor) { // already focused
myCurrentEditor = editor;
}
EmptyAction.registerActionShortcuts(editor.getComponent(), myConsoleEditor.getComponent());
}
}
@Override
public void fileClosed(@NotNull FileEditorManager source, @NotNull VirtualFile file) {
if (!Comparing.equal(file, getVirtualFile())) {
return;
}
if (!Boolean.TRUE.equals(file.getUserData(FileEditorManagerImpl.CLOSING_TO_REOPEN))) {
if (myCurrentEditor != null && myCurrentEditor.isDisposed()) {
myCurrentEditor = null;
}
}
}
};
myBusConnection.subscribe(FileEditorManagerListener.FILE_EDITOR_MANAGER, fileEditorListener);
FileEditorManager editorManager = FileEditorManager.getInstance(getProject());
if (editorManager.isFileOpen(getVirtualFile())) {
fileEditorListener.fileOpened(editorManager, getVirtualFile());
}
}
@Override
public void dispose() {
myBusConnection.deliverImmediately();
Disposer.dispose(myBusConnection);
EditorFactory editorFactory = EditorFactory.getInstance();
editorFactory.releaseEditor(myConsoleEditor);
}
public void setInputText(@NotNull final String query) {
DocumentUtil.writeInRunUndoTransparentAction(() -> myConsoleEditor.getDocument().setText(StringUtil.convertLineSeparators(query)));
}
}
@@ -5,37 +5,31 @@ import com.intellij.execution.impl.ConsoleViewImpl;
import com.intellij.execution.impl.ConsoleViewUtil;
import com.intellij.execution.ui.ConsoleViewContentType;
import com.intellij.ide.DataManager;
import com.intellij.ide.GeneralSettings;
import com.intellij.ide.highlighter.HighlighterFactory;
import com.intellij.injected.editor.EditorWindow;
import com.intellij.lang.Language;
import com.intellij.openapi.actionSystem.DataProvider;
import com.intellij.openapi.actionSystem.EmptyAction;
import com.intellij.openapi.actionSystem.IdeActions;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.application.ReadAction;
import com.intellij.openapi.application.TransactionGuard;
import com.intellij.openapi.command.undo.UndoUtil;
import com.intellij.openapi.editor.*;
import com.intellij.openapi.editor.colors.EditorColorsManager;
import com.intellij.openapi.editor.event.DocumentEvent;
import com.intellij.openapi.editor.event.DocumentListener;
import com.intellij.openapi.editor.ex.EditorEx;
import com.intellij.openapi.editor.ex.FocusChangeListener;
import com.intellij.openapi.editor.ex.util.EditorUtil;
import com.intellij.openapi.editor.ex.util.LexerEditorHighlighter;
import com.intellij.openapi.editor.highlighter.EditorHighlighter;
import com.intellij.openapi.editor.highlighter.EditorHighlighterFactory;
import com.intellij.openapi.editor.impl.EditorFactoryImpl;
import com.intellij.openapi.fileEditor.*;
import com.intellij.openapi.fileEditor.FileDocumentManager;
import com.intellij.openapi.fileEditor.FileEditorManager;
import com.intellij.openapi.fileEditor.OpenFileDescriptor;
import com.intellij.openapi.fileEditor.ex.FileEditorManagerEx;
import com.intellij.openapi.fileEditor.impl.FileEditorManagerImpl;
import com.intellij.openapi.fileTypes.SyntaxHighlighter;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.Comparing;
import com.intellij.openapi.util.Disposer;
import com.intellij.openapi.util.TextRange;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.openapi.wm.IdeFocusManager;
import com.intellij.psi.PsiFile;
@@ -47,8 +41,6 @@ import com.intellij.ui.components.JBScrollBar;
import com.intellij.ui.components.JBScrollPane.Alignment;
import com.intellij.util.DocumentUtil;
import com.intellij.util.FileContentUtil;
import com.intellij.util.ObjectUtils;
import com.intellij.util.messages.MessageBusConnection;
import com.intellij.util.ui.AbstractLayoutManager;
import com.intellij.util.ui.JBUI;
import com.intellij.util.ui.UIUtil;
@@ -69,10 +61,8 @@ import java.util.Collections;
public class LanguageConsoleImpl extends ConsoleViewImpl implements LanguageConsoleView, DataProvider {
private final Helper myHelper;
private final EditorEx myConsoleEditor;
private final ConsoleExecutionEditor myConsoleExecutionEditor;
private final EditorEx myHistoryViewer;
private final Document myEditorDocument;
private final JPanel myPanel = new JPanel(new MyLayout());
private final JScrollBar myScrollBar = new JBScrollBar(Adjustable.HORIZONTAL);
private final DocumentListener myDocumentAdapter = new DocumentListener() {
@@ -82,27 +72,6 @@ public class LanguageConsoleImpl extends ConsoleViewImpl implements LanguageCons
}
};
@Nullable
private String myPrompt = "> ";
private ConsoleViewContentType myPromptAttributes = ConsoleViewContentType.USER_INPUT;
private EditorEx myCurrentEditor;
private final MessageBusConnection myBusConnection;
private final FocusChangeListener myFocusListener = new FocusChangeListener() {
@Override
public void focusGained(@NotNull Editor editor) {
myCurrentEditor = (EditorEx)editor;
if (GeneralSettings.getInstance().isSaveOnFrameDeactivation()) {
TransactionGuard.submitTransaction(LanguageConsoleImpl.this, () -> FileDocumentManager.getInstance().saveAllDocuments()); // PY-12487
}
}
@Override
public void focusLost(@NotNull Editor editor) {
}
};
public LanguageConsoleImpl(@NotNull Project project, @NotNull String title, @NotNull Language language) {
this(new Helper(project, new LightVirtualFile(title, language, "")));
}
@@ -115,24 +84,15 @@ public class LanguageConsoleImpl extends ConsoleViewImpl implements LanguageCons
super(helper.project, GlobalSearchScope.allScope(helper.project), true, true);
myHelper = helper;
EditorFactory editorFactory = EditorFactory.getInstance();
myEditorDocument = helper.getDocument();
myConsoleEditor = (EditorEx)editorFactory.createEditor(myEditorDocument, getProject());
myConsoleEditor.getDocument().addDocumentListener(myDocumentAdapter);
myConsoleEditor.getScrollPane().getHorizontalScrollBar().setEnabled(false);
myConsoleEditor.addFocusListener(myFocusListener);
myConsoleEditor.getSettings().setVirtualSpace(false);
myCurrentEditor = myConsoleEditor;
myConsoleExecutionEditor = new ConsoleExecutionEditor(helper);
Disposer.register(this, myConsoleExecutionEditor);
Document historyDocument = ((EditorFactoryImpl)editorFactory).createDocument(true);
UndoUtil.disableUndoFor(historyDocument);
myHistoryViewer = (EditorEx)editorFactory.createViewer(historyDocument, getProject(), EditorKind.CONSOLE);
myHistoryViewer.getDocument().addDocumentListener(myDocumentAdapter);
myScrollBar.setModel(new MyModel(myScrollBar, myHistoryViewer, myConsoleEditor));
myConsoleExecutionEditor.getDocument().addDocumentListener(myDocumentAdapter);
myScrollBar.setModel(new MyModel(myScrollBar, myHistoryViewer, myConsoleExecutionEditor.getEditor()));
myScrollBar.putClientProperty(Alignment.class, Alignment.BOTTOM);
myBusConnection = getProject().getMessageBus().connect();
// action shortcuts are not yet registered
ApplicationManager.getApplication().invokeLater(() -> installEditorFactoryListener(), getProject().getDisposed());
}
@NotNull
@@ -161,12 +121,10 @@ public class LanguageConsoleImpl extends ConsoleViewImpl implements LanguageCons
setupComponents();
myPanel.add(myHistoryViewer.getComponent());
myPanel.add(myConsoleEditor.getComponent());
myPanel.add(myConsoleExecutionEditor.getComponent());
myPanel.add(myScrollBar);
myPanel.setBackground(myConsoleEditor.getBackgroundColor());
myPanel.setBackground(myConsoleExecutionEditor.getEditor().getBackgroundColor());
DataManager.registerDataProvider(myPanel, this);
setPromptInner(myPrompt);
}
@Override
@@ -174,13 +132,9 @@ public class LanguageConsoleImpl extends ConsoleViewImpl implements LanguageCons
if (isConsoleEditorEnabled() == consoleEditorEnabled) {
return;
}
if (consoleEditorEnabled) {
FileEditorManager.getInstance(getProject()).closeFile(getVirtualFile());
myCurrentEditor = myConsoleEditor;
}
myConsoleExecutionEditor.setConsoleEditorEnabled(consoleEditorEnabled);
setHistoryScrollBarVisible(!consoleEditorEnabled);
myScrollBar.setVisible(consoleEditorEnabled);
myConsoleEditor.getComponent().setVisible(consoleEditorEnabled);
}
private void setHistoryScrollBarVisible(boolean visible) {
@@ -189,16 +143,14 @@ public class LanguageConsoleImpl extends ConsoleViewImpl implements LanguageCons
}
private void setupComponents() {
myHelper.setupEditor(myConsoleEditor);
myHelper.setupEditor(myConsoleExecutionEditor.getEditor());
myHelper.setupEditor(myHistoryViewer);
myHistoryViewer.getComponent().setMinimumSize(JBUI.emptySize());
myHistoryViewer.getComponent().setPreferredSize(JBUI.emptySize());
myHistoryViewer.setCaretEnabled(false);
myConsoleEditor.setContextMenuGroupId(IdeActions.GROUP_CONSOLE_EDITOR_POPUP);
myConsoleEditor.setHighlighter(
EditorHighlighterFactory.getInstance().createEditorHighlighter(getVirtualFile(), myConsoleEditor.getColorsScheme(), getProject()));
myConsoleExecutionEditor.initComponent();
setHistoryScrollBarVisible(false);
@@ -206,61 +158,52 @@ public class LanguageConsoleImpl extends ConsoleViewImpl implements LanguageCons
@Override
public void keyTyped(KeyEvent event) {
if (isConsoleEditorEnabled() && UIUtil.isReallyTypedEvent(event)) {
IdeFocusManager.getGlobalInstance().doWhenFocusSettlesDown(() -> IdeFocusManager.getGlobalInstance().requestFocus(myConsoleEditor.getContentComponent(), true));
myConsoleEditor.processKeyTyped(event);
IdeFocusManager.getGlobalInstance().doWhenFocusSettlesDown(
() -> IdeFocusManager.getGlobalInstance().requestFocus(myConsoleExecutionEditor.getEditor().getContentComponent(), true)
);
myConsoleExecutionEditor.getEditor().processKeyTyped(event);
}
}
});
EmptyAction.registerActionShortcuts(myHistoryViewer.getComponent(), myConsoleEditor.getComponent());
EmptyAction.registerActionShortcuts(myHistoryViewer.getComponent(), myConsoleExecutionEditor.getComponent());
}
@Override
public final boolean isConsoleEditorEnabled() {
return myConsoleEditor.getComponent().isVisible();
return myConsoleExecutionEditor.isConsoleEditorEnabled();
}
@Override
@Nullable
public String getPrompt() {
return myPrompt;
return myConsoleExecutionEditor.getPrompt();
}
@Override
@Nullable
public ConsoleViewContentType getPromptAttributes() {
return myPromptAttributes;
return myConsoleExecutionEditor.getPromptAttributes();
}
@Override
public void setPromptAttributes(@NotNull ConsoleViewContentType textAttributes) {
myPromptAttributes = textAttributes;
myConsoleExecutionEditor.setPromptAttributes(textAttributes);
}
@Override
public void setPrompt(@Nullable String prompt) {
// always add space to the prompt otherwise it may look ugly
myPrompt = prompt != null && !prompt.endsWith(" ") ? prompt + " " : prompt;
setPromptInner(myPrompt);
}
private void setPromptInner(@Nullable final String prompt) {
UIUtil.invokeAndWaitIfNeeded((Runnable)() -> {
if (!myConsoleEditor.isDisposed()) {
myConsoleEditor.setPrefixTextAndAttributes(prompt, myPromptAttributes.getAttributes());
}
});
myConsoleExecutionEditor.setPrompt(prompt);
}
@Override
public void setEditable(boolean editable) {
myConsoleEditor.setRendererMode(!editable);
setPromptInner(editable ? myPrompt : "");
myConsoleExecutionEditor.setEditable(editable);
}
@Override
public boolean isEditable() {
return !myConsoleEditor.isRendererMode();
return myConsoleExecutionEditor.isEditable();
}
@Override
@@ -272,7 +215,7 @@ public class LanguageConsoleImpl extends ConsoleViewImpl implements LanguageCons
@Override
@NotNull
public final VirtualFile getVirtualFile() {
return myHelper.virtualFile;
return myConsoleExecutionEditor.getVirtualFile();
}
@Override
@@ -284,13 +227,13 @@ public class LanguageConsoleImpl extends ConsoleViewImpl implements LanguageCons
@Override
@NotNull
public final Document getEditorDocument() {
return myEditorDocument;
return myConsoleExecutionEditor.getDocument();
}
@Override
@NotNull
public final EditorEx getConsoleEditor() {
return myConsoleEditor;
return myConsoleExecutionEditor.getEditor();
}
@Override
@@ -382,8 +325,8 @@ public class LanguageConsoleImpl extends ConsoleViewImpl implements LanguageCons
}
protected void doAddPromptToHistory() {
if (myPrompt != null) {
print(myPrompt, myPromptAttributes);
if (myConsoleExecutionEditor.getPrompt() != null) {
print(myConsoleExecutionEditor.getPrompt(), myConsoleExecutionEditor.getPromptAttributes());
}
}
@@ -421,14 +364,10 @@ public class LanguageConsoleImpl extends ConsoleViewImpl implements LanguageCons
// double dispose via RunContentDescriptor and ContentImpl
if (myHistoryViewer.isDisposed()) return;
myConsoleEditor.getDocument().removeDocumentListener(myDocumentAdapter);
myConsoleExecutionEditor.getDocument().removeDocumentListener(myDocumentAdapter);
myHistoryViewer.getDocument().removeDocumentListener(myDocumentAdapter);
myBusConnection.deliverImmediately();
Disposer.dispose(myBusConnection);
EditorFactory editorFactory = EditorFactory.getInstance();
editorFactory.releaseEditor(myConsoleEditor);
editorFactory.releaseEditor(myHistoryViewer);
if (getProject().isOpen()) {
@@ -445,52 +384,11 @@ public class LanguageConsoleImpl extends ConsoleViewImpl implements LanguageCons
return super.getData(dataId);
}
private void installEditorFactoryListener() {
FileEditorManagerListener fileEditorListener = new FileEditorManagerListener() {
@Override
public void fileOpened(@NotNull FileEditorManager source, @NotNull VirtualFile file) {
if (myConsoleEditor == null || !Comparing.equal(file, getVirtualFile())) {
return;
}
Editor selectedTextEditor = source.getSelectedTextEditor();
for (FileEditor fileEditor : source.getAllEditors(file)) {
if (!(fileEditor instanceof TextEditor)) {
continue;
}
final EditorEx editor = (EditorEx)((TextEditor)fileEditor).getEditor();
editor.addFocusListener(myFocusListener);
if (selectedTextEditor == editor) { // already focused
myCurrentEditor = editor;
}
EmptyAction.registerActionShortcuts(editor.getComponent(), myConsoleEditor.getComponent());
}
}
@Override
public void fileClosed(@NotNull FileEditorManager source, @NotNull VirtualFile file) {
if (!Comparing.equal(file, getVirtualFile())) {
return;
}
if (!Boolean.TRUE.equals(file.getUserData(FileEditorManagerImpl.CLOSING_TO_REOPEN))) {
if (myCurrentEditor != null && myCurrentEditor.isDisposed()) {
myCurrentEditor = null;
}
}
}
};
myBusConnection.subscribe(FileEditorManagerListener.FILE_EDITOR_MANAGER, fileEditorListener);
FileEditorManager editorManager = FileEditorManager.getInstance(getProject());
if (editorManager.isFileOpen(getVirtualFile())) {
fileEditorListener.fileOpened(editorManager, getVirtualFile());
}
}
@Override
@NotNull
public EditorEx getCurrentEditor() {
return ObjectUtils.notNull(myCurrentEditor, myConsoleEditor);
return myConsoleExecutionEditor.getCurrentEditor();
}
@Override
@@ -507,7 +405,7 @@ public class LanguageConsoleImpl extends ConsoleViewImpl implements LanguageCons
@Override
public void setInputText(@NotNull final String query) {
DocumentUtil.writeInRunUndoTransparentAction(() -> myConsoleEditor.getDocument().setText(StringUtil.convertLineSeparators(query)));
myConsoleExecutionEditor.setInputText(query);
}
boolean isHistoryViewerForceAdditionalColumnsUsage() {
@@ -530,6 +428,10 @@ public class LanguageConsoleImpl extends ConsoleViewImpl implements LanguageCons
title = virtualFile.getName();
}
public String getTitle() {
return this.title;
}
public Helper setTitle(String title) {
this.title = title;
return this;
@@ -576,7 +478,7 @@ public class LanguageConsoleImpl extends ConsoleViewImpl implements LanguageCons
}
@NotNull
PsiFile getFileSafe() {
public PsiFile getFileSafe() {
return file == null || !file.isValid() ? file = getFile() : file;
}
@@ -607,7 +509,7 @@ public class LanguageConsoleImpl extends ConsoleViewImpl implements LanguageCons
}
final EditorEx history = myHistoryViewer;
final EditorEx input = isConsoleEditorEnabled() ? myConsoleEditor : null;
final EditorEx input = isConsoleEditorEnabled() ? myConsoleExecutionEditor.getEditor() : null;
if (input == null) {
parent.getComponent(0).setBounds(parent.getBounds());
return;
@@ -17,6 +17,7 @@ import org.jetbrains.annotations.Nullable;
import javax.swing.*;
import java.awt.*;
import java.awt.event.KeyListener;
import java.util.ArrayList;
import java.util.List;
@@ -103,6 +104,11 @@ public class JavaFxHtmlPanel implements Disposable {
public void dispose() {
}
public void addKeyListener(KeyListener l) {
runInPlatformWhenAvailable(() -> myPanel.addKeyListener(l));
}
@NotNull
protected WebView getWebViewGuaranteed() {
if (myWebView == null) {