@Override
    public void layoutContainer(final Container parent) {
      final int componentCount = parent.getComponentCount();
      if (componentCount == 0) return;
      final EditorEx history = myHistoryViewer;
      final EditorEx editor = componentCount == 2 ? myConsoleEditor : null;

      if (editor == null) {
        parent.getComponent(0).setBounds(parent.getBounds());
        return;
      }

      final Dimension panelSize = parent.getSize();
      if (panelSize.getHeight() <= 0) return;
      final Dimension historySize = history.getContentSize();
      final Dimension editorSize = editor.getContentSize();
      final Dimension newEditorSize = new Dimension();

      // deal with width
      final int width = Math.max(editorSize.width, historySize.width);
      newEditorSize.width = width + editor.getScrollPane().getHorizontalScrollBar().getHeight();
      history.getSoftWrapModel().forceAdditionalColumnsUsage();
      editor
          .getSettings()
          .setAdditionalColumnsCount(
              2 + (width - editorSize.width) / EditorUtil.getSpaceWidth(Font.PLAIN, editor));
      history
          .getSettings()
          .setAdditionalColumnsCount(
              2 + (width - historySize.width) / EditorUtil.getSpaceWidth(Font.PLAIN, history));

      // deal with height
      if (historySize.width == 0) historySize.height = 0;
      final int minHistorySize =
          historySize.height > 0
              ? 2 * history.getLineHeight() + (myShowSeparatorLine ? SEPARATOR_THICKNESS : 0)
              : 0;
      final int minEditorSize = editor.isViewer() ? 0 : editor.getLineHeight();
      final int editorPreferred =
          editor.isViewer() ? 0 : Math.max(minEditorSize, editorSize.height);
      final int historyPreferred = Math.max(minHistorySize, historySize.height);
      if (panelSize.height < minEditorSize) {
        newEditorSize.height = panelSize.height;
      } else if (panelSize.height < editorPreferred) {
        newEditorSize.height = panelSize.height - minHistorySize;
      } else if (panelSize.height < editorPreferred + historyPreferred) {
        newEditorSize.height = editorPreferred;
      } else {
        newEditorSize.height = editorPreferred == 0 ? 0 : panelSize.height - historyPreferred;
      }
      final Dimension newHistorySize =
          new Dimension(width, panelSize.height - newEditorSize.height);

      // apply
      editor
          .getComponent()
          .setBounds(0, newHistorySize.height, panelSize.width, newEditorSize.height);
      myForceScrollToEnd.compareAndSet(false, shouldScrollHistoryToEnd());
      history.getComponent().setBounds(0, 0, panelSize.width, newHistorySize.height);
    }
 private static void duplicateHighlighters(
     MarkupModel to, MarkupModel from, int offset, TextRange textRange) {
   for (RangeHighlighter rangeHighlighter : from.getAllHighlighters()) {
     if (!rangeHighlighter.isValid()) continue;
     Object tooltip = rangeHighlighter.getErrorStripeTooltip();
     HighlightInfo highlightInfo =
         tooltip instanceof HighlightInfo ? (HighlightInfo) tooltip : null;
     if (highlightInfo != null) {
       if (highlightInfo.getSeverity() != HighlightSeverity.INFORMATION) continue;
       if (highlightInfo.type.getAttributesKey() == EditorColors.IDENTIFIER_UNDER_CARET_ATTRIBUTES)
         continue;
     }
     final int localOffset = textRange.getStartOffset();
     final int start = Math.max(rangeHighlighter.getStartOffset(), localOffset) - localOffset;
     final int end =
         Math.min(rangeHighlighter.getEndOffset(), textRange.getEndOffset()) - localOffset;
     if (start > end) continue;
     final RangeHighlighter h =
         to.addRangeHighlighter(
             start + offset,
             end + offset,
             rangeHighlighter.getLayer(),
             rangeHighlighter.getTextAttributes(),
             rangeHighlighter.getTargetArea());
     ((RangeHighlighterEx) h)
         .setAfterEndOfLine(((RangeHighlighterEx) rangeHighlighter).isAfterEndOfLine());
   }
 }
  @Override
  @NotNull
  public String getPlainText() {
    int startOffset = getNavigationOffset();
    final PsiElement element = getElement();
    if (element != null && startOffset != -1) {
      final Document document = getDocument();
      if (document != null) {
        int lineNumber = document.getLineNumber(startOffset);
        int lineStart = document.getLineStartOffset(lineNumber);
        int lineEnd = document.getLineEndOffset(lineNumber);
        String prefixSuffix = null;

        if (lineEnd - lineStart > ChunkExtractor.MAX_LINE_LENGTH_TO_SHOW) {
          prefixSuffix = "...";
          lineStart =
              Math.max(
                  startOffset - ChunkExtractor.OFFSET_BEFORE_TO_SHOW_WHEN_LONG_LINE, lineStart);
          lineEnd =
              Math.min(startOffset + ChunkExtractor.OFFSET_AFTER_TO_SHOW_WHEN_LONG_LINE, lineEnd);
        }
        String s = document.getCharsSequence().subSequence(lineStart, lineEnd).toString();
        if (prefixSuffix != null) s = prefixSuffix + s + prefixSuffix;
        return s;
      }
    }
    return UsageViewBundle.message("node.invalid");
  }
 int getNavigationOffset() {
   Document document = getDocument();
   if (document == null) return -1;
   int offset = getUsageInfo().getNavigationOffset();
   if (offset == -1) offset = myOffset;
   if (offset >= document.getTextLength()) {
     int line = Math.max(0, Math.min(myLineNumber, document.getLineCount() - 1));
     offset = document.getLineStartOffset(line);
   }
   return offset;
 }
  protected String addTextRangeToHistory(
      TextRange textRange, final EditorEx consoleEditor, boolean preserveMarkup) {
    final Document history = myHistoryViewer.getDocument();
    final MarkupModel markupModel = DocumentMarkupModel.forDocument(history, myProject, true);
    if (myPrompt != null) {
      appendToHistoryDocument(history, myPrompt);
    }
    markupModel.addRangeHighlighter(
        history.getTextLength() - StringUtil.length(myPrompt),
        history.getTextLength(),
        HighlighterLayer.SYNTAX,
        ConsoleViewContentType.USER_INPUT.getAttributes(),
        HighlighterTargetArea.EXACT_RANGE);
    final int localStartOffset = textRange.getStartOffset();
    String text;
    EditorHighlighter highlighter;
    if (consoleEditor instanceof EditorWindow) {
      EditorWindow editorWindow = (EditorWindow) consoleEditor;
      EditorColorsScheme scheme = EditorColorsManager.getInstance().getGlobalScheme();
      PsiFile file = editorWindow.getInjectedFile();
      final VirtualFile virtualFile = file.getVirtualFile();
      assert virtualFile != null;
      highlighter = HighlighterFactory.createHighlighter(virtualFile, scheme, getProject());
      String fullText = InjectedLanguageUtil.getUnescapedText(file, null, null);
      highlighter.setText(fullText);
      text = textRange.substring(fullText);
    } else {
      text = consoleEditor.getDocument().getText(textRange);
      highlighter = consoleEditor.getHighlighter();
    }
    // offset can be changed after text trimming after insert due to buffer constraints
    appendToHistoryDocument(history, text);
    int offset = history.getTextLength() - text.length();

    final HighlighterIterator iterator = highlighter.createIterator(localStartOffset);
    final int localEndOffset = textRange.getEndOffset();
    while (!iterator.atEnd()) {
      final int itStart = iterator.getStart();
      if (itStart > localEndOffset) break;
      final int itEnd = iterator.getEnd();
      if (itEnd >= localStartOffset) {
        final int start = Math.max(itStart, localStartOffset) - localStartOffset + offset;
        final int end = Math.min(itEnd, localEndOffset) - localStartOffset + offset;
        markupModel.addRangeHighlighter(
            start,
            end,
            HighlighterLayer.SYNTAX,
            iterator.getTextAttributes(),
            HighlighterTargetArea.EXACT_RANGE);
      }
      iterator.advance();
    }
    if (preserveMarkup) {
      duplicateHighlighters(
          markupModel,
          DocumentMarkupModel.forDocument(consoleEditor.getDocument(), myProject, true),
          offset,
          textRange);
      duplicateHighlighters(markupModel, consoleEditor.getMarkupModel(), offset, textRange);
    }
    if (!text.endsWith("\n")) {
      appendToHistoryDocument(history, "\n");
    }
    return text;
  }