@Override
  protected void init() {
    initMnemonics();

    initTree(myPsiTree);
    TreeCellRenderer renderer = myPsiTree.getCellRenderer();
    myPsiTree.setCellRenderer((tree, value, selected, expanded, leaf, row, hasFocus) -> {
      Component c = renderer.getTreeCellRendererComponent(tree, value, selected, expanded, leaf, row, hasFocus);
      if (value instanceof DefaultMutableTreeNode) {
        Object userObject = ((DefaultMutableTreeNode)value).getUserObject();
        if (userObject instanceof ViewerNodeDescriptor descriptor) {
          Object element = descriptor.getElement();
          if (c instanceof NodeRenderer nodeRenderer) {
            nodeRenderer.setToolTipText(getElementDescription(element));
          }

          PsiElement fileContext = null;
          if (element instanceof PsiElement psiElement) {
            PsiFile containingFile = ReadAction.compute(psiElement::getContainingFile);
            if (containingFile != null) fileContext = FileContextUtil.getFileContext(containingFile);
          }

          boolean isInjected = (element instanceof ViewerTreeStructure.Inject) || fileContext != null;
          if (isInjected) {
            TextAttributes attr =
              EditorColorsManager.getInstance().getGlobalScheme().getAttributes(EditorColors.INJECTED_LANGUAGE_FRAGMENT);
            c.setBackground(attr.getBackgroundColor());
          }
        }
      }
      return c;
    });
    myPsiTree.addTreeSelectionListener(new MyPsiTreeSelectionListener());

    myPsiTreePanel.add(myPsiTreeSeparator, BorderLayout.NORTH);

    JScrollPane scrollPane = ScrollPaneFactory.createScrollPane(myPsiTree, true);
    myPsiTreePanel.add(scrollPane, BorderLayout.CENTER);

    myTreeSplit.add(myPsiTreePanel, JSplitPane.LEFT);
    myTreeSplit.add(myTabs.getComponent(), JSplitPane.RIGHT);

    JPanel referencesPanel = new JPanel(new BorderLayout());
    referencesPanel.add(myRefs);

    var propertiesTab = new PsiViewerPropertiesTab(myPsiViewerPropertiesTabViewModel, myCoroutineScope);
    var propertiesTabInfo = new TabInfo(propertiesTab.getComponent()).setText(DevPsiViewerBundle.message("tab.title.properties"));
    myTabs.addTab(propertiesTabInfo);
    myTabs.addTab(new TabInfo(myRefs).setText(DevPsiViewerBundle.message("tab.title.references")));
    myTabs.addTab(new TabInfo(myBlockTree.getComponent()).setText(DevPsiViewerBundle.message("tab.title.block.structure")));
    myTabs.addTab(new TabInfo(myStubTree.getComponent()).setText(DevPsiViewerBundle.message("tab.title.stub.structure")));

    PsiViewerSettings settings = PsiViewerSettings.getSettings();
    myTabs.setSelectionChangeHandler((tab, focus, el) -> {
      settings.lastSelectedTabIndex = myTabs.getIndexOf(tab);
      if (tab == propertiesTabInfo) {
        myPsiViewerPropertiesTabViewModel.openTab();
      } else {
        myPsiViewerPropertiesTabViewModel.closeTab();
      }
      return el.run();
    });
    int tabIndex = settings.lastSelectedTabIndex;
    TabInfo defaultInfo = tabIndex < myTabs.getTabCount() ? myTabs.getTabAt(tabIndex) : null;
    if (defaultInfo != null) {
      myTabs.select(defaultInfo, false);
    }

    GoToListener listener = new GoToListener();
    myRefs.addKeyListener(listener);
    myRefs.addMouseListener(listener);
    myRefs.getSelectionModel().addListSelectionListener(listener);
    myRefs.setCellRenderer(new DefaultListCellRenderer() {
      @Override
      public Component getListCellRendererComponent(@NotNull JList list,
                                                    Object value,
                                                    int index,
                                                    boolean isSelected,
                                                    boolean cellHasFocus) {
        Component comp = super.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus);
        PsiElement[] elements = myRefsResolvedCache.get(getPsiElement());
        if (elements == null || elements.length <= index || elements[index] == null) {
          comp.setForeground(JBColor.RED);
        }
        return comp;
      }
    });

    myEditor.getSettings().setFoldingOutlineShown(false);
    myEditor.getDocument().addDocumentListener(myEditorListener, getDisposable());
    myEditor.getSelectionModel().addSelectionListener(myEditorListener);
    myEditor.getCaretModel().addCaretListener(myEditorListener);

    FocusTraversalPolicy oldPolicy = getPeer().getWindow().getFocusTraversalPolicy();
    getPeer().getWindow().setFocusTraversalPolicy(new LayoutFocusTraversalPolicy() {
      @Override
      public Component getInitialComponent(@NotNull Window window) {
        return myEditor.getComponent();
      }
    });
    Disposer.register(getDisposable(), () -> getPeer().getWindow().setFocusTraversalPolicy(oldPolicy));
    VirtualFile file = myExternalDocument ? FileDocumentManager.getInstance().getFile(myEditor.getDocument()) : null;
    Language curLanguage = LanguageUtil.getLanguageForPsi(myProject, file);

    String type = curLanguage != null ? curLanguage.getDisplayName() : settings.type;
    PsiViewerSourceWrapper lastUsed = null;
    mySourceWrappers.addAll(PsiViewerSourceWrapper.getExtensionBasedWrappers());

    List<PsiViewerSourceWrapper> fileTypeBasedWrappers = PsiViewerSourceWrapper.getFileTypeBasedWrappers();
    for (PsiViewerSourceWrapper wrapper : fileTypeBasedWrappers) {
      mySourceWrappers.addAll(fileTypeBasedWrappers);
      if (lastUsed == null && wrapper.getText().equals(type) ||
          curLanguage != null && wrapper.myFileType == curLanguage.getAssociatedFileType()) {
        lastUsed = wrapper;
      }
    }

    myFileTypeComboBox.setSwingPopup(false);
    myFileTypeComboBox.setModel(new CollectionComboBoxModel<>(new ArrayList<>(mySourceWrappers), lastUsed));
    myFileTypeComboBox.setRenderer(SimpleListCellRenderer.create((label, value, index) -> {
      if (value != null) {
        label.setText(value.getText());
        label.setIcon(value.getIcon());
      }
    }));
    ComboboxSpeedSearch search1 = new ComboboxSpeedSearch(myFileTypeComboBox, null) {
      @Override
      protected String getElementText(Object element) {
        return element instanceof PsiViewerSourceWrapper ? ((PsiViewerSourceWrapper)element).getText() : null;
      }
    };
    search1.setupListeners();
    myFileTypeComboBox.addActionListener(__ -> {
      updateDialectsCombo(null);
      updateExtensionsCombo();
      updateEditor();
    });
    myDialectComboBox.addActionListener(__ -> updateEditor());
    ComboboxSpeedSearch search = new ComboboxSpeedSearch(myDialectComboBox, null) {
      @Override
      protected String getElementText(Object element) {
        return element instanceof Language ? ((Language)element).getDisplayName() : "<default>";
      }
    };
    search.setupListeners();
    myFileTypeComboBox.addFocusListener(new AutoExpandFocusListener(myFileTypeComboBox));
    if (!myExternalDocument && lastUsed == null && !mySourceWrappers.isEmpty()) {
      myFileTypeComboBox.setSelectedIndex(0);
    }

    myDialectComboBox.setRenderer(SimpleListCellRenderer.create(DevPsiViewerBundle.message("label.none"), value -> value.getDisplayName()));
    myDialectComboBox.addFocusListener(new AutoExpandFocusListener(myDialectComboBox));
    myExtensionComboBox.setRenderer(SimpleListCellRenderer.create("", value -> "." + value)); //NON-NLS
    myExtensionComboBox.addFocusListener(new AutoExpandFocusListener(myExtensionComboBox));

    myShowWhiteSpacesBox.addActionListener(__ -> {
      myTreeStructure.setShowWhiteSpaces(myShowWhiteSpacesBox.isSelected());
      myStructureTreeModel.invalidateAsync();
    });
    myShowTreeNodesCheckBox.addActionListener(__ -> {
      myTreeStructure.setShowTreeNodes(myShowTreeNodesCheckBox.isSelected());
      myStructureTreeModel.invalidateAsync();
    });
    myShowEmptyPropertiesCheckBox.addActionListener(__ -> {
      myPsiViewerPropertiesTabViewModel.setShowEmptyProperties(myShowEmptyPropertiesCheckBox.isSelected());
    });
    myUpdatePsiTreeCheckbox.addActionListener(__ -> {
      var isSelected = myUpdatePsiTreeCheckbox.isSelected();
      settings.updatePsiTreeOnChanges = isSelected;
      if (isSelected) {
        queueUpdatePsi();
      }
    });
    myShowWhiteSpacesBox.setSelected(settings.showWhiteSpaces);
    myTreeStructure.setShowWhiteSpaces(settings.showWhiteSpaces);
    myShowTreeNodesCheckBox.setSelected(settings.showTreeNodes);
    myTreeStructure.setShowTreeNodes(settings.showTreeNodes);
    myShowEmptyPropertiesCheckBox.setSelected(myPsiViewerPropertiesTabViewModel.getShowEmptyProperties());
    myUpdatePsiTreeCheckbox.setSelected(settings.updatePsiTreeOnChanges);
    myTextPanel.setLayout(new BorderLayout());
    myTextPanel.add(myEditor.getComponent(), BorderLayout.CENTER);

    updateDialectsCombo(settings.dialect);
    updateExtensionsCombo();

    registerCustomKeyboardActions();

    Dimension size = DimensionService.getInstance().getSize(getDimensionServiceKey(), myProject);
    if (size == null) {
      DimensionService.getInstance().setSize(getDimensionServiceKey(), JBUI.size(800, 600), myProject);
    }
    myTextSplit.setDividerLocation(settings.textDividerLocation);
    myTreeSplit.setDividerLocation(settings.treeDividerLocation);

    updateEditor();
    //GuiUtils.replaceJSplitPaneWithIDEASplitter(myTreeSplit, true);
    GuiUtils.replaceJSplitPaneWithIDEASplitter(myTextSplit, true);
    super.init();
  }
@Override
  protected void init()