private BeforeAfter<Integer> getEditorLines() {
    final Editor editor = ((DiffPanelImpl) getCurrentPanel()).getEditor1();
    Rectangle visibleArea = editor.getScrollingModel().getVisibleArea();
    final int offset = editor.getScrollingModel().getVerticalScrollOffset();

    int leftPixels = offset % editor.getLineHeight();

    final Point start = visibleArea.getLocation();
    final LogicalPosition startLp = editor.xyToLogicalPosition(start);
    final Point location = new Point(start.x + visibleArea.width, start.y + visibleArea.height);
    final LogicalPosition lp = editor.xyToLogicalPosition(location);

    int curStartLine =
        startLp.line == (editor.getDocument().getLineCount() - 1)
            ? startLp.line
            : (startLp.line + 1);
    int cutEndLine = lp.line == 0 ? 0 : lp.line - 1;

    boolean commonPartOk = leftPixels == 0 || startLp.line == lp.line;
    return new BeforeAfter<Integer>(
        commonPartOk && startLp.softWrapLinesOnCurrentLogicalLine == 0
            ? startLp.line
            : curStartLine,
        commonPartOk && lp.softWrapLinesOnCurrentLogicalLine == 0 ? lp.line : cutEndLine);
    /*if (leftPixels == 0 || startLp.line == lp.line) {
      return new BeforeAfter<Integer>(startLp.line, lp.line);
    } else {
      return new BeforeAfter<Integer>(curStartLine, cutEndLine);
    }*/
  }
    private void recalculateMaxValues() {
      myIdxLeft = widestEditor(myLeftEditors);
      final Editor leftEditor = myLeftEditors.get(myIdxLeft);
      final int wholeWidth = leftEditor.getContentComponent().getWidth();
      final Rectangle va = leftEditor.getScrollingModel().getVisibleArea();
      final int visibleLeft = leftEditor.xyToVisualPosition(new Point(va.width, 0)).column;

      myMaxColumnsLeft = (int) (visibleLeft * ((double) wholeWidth / va.getWidth()));

      myIdxRight = widestEditor(myRightEditors);
      final Editor rightEditor = myRightEditors.get(myIdxRight);
      final int wholeWidthRight = rightEditor.getContentComponent().getWidth();
      final Rectangle vaRight = rightEditor.getScrollingModel().getVisibleArea();
      final int visibleRight = rightEditor.xyToVisualPosition(new Point(va.width, 0)).column;

      myMaxColumnsRight = (int) (visibleRight * ((double) wholeWidthRight / vaRight.getWidth()));

      myByLeft = !(myMaxColumnsLeft <= visibleLeft);
      if (!myByLeft) {
        // check right editor
        if (myLeftScroll.getVisibleAmount() != visibleRight) {
          myLeftScroll.setVisibleAmount(visibleRight);
        }
        myLeftScroll.setMaximum(myMaxColumnsRight);
      } else {
        if (myLeftScroll.getVisibleAmount() != visibleLeft) {
          myLeftScroll.setVisibleAmount(visibleLeft);
        }
        myLeftScroll.setMaximum(myMaxColumnsLeft);
      }
    }
  private void updateCursorHighlighting(boolean scroll) {
    hideBalloon();

    if (myCursorHighlighter != null) {
      HighlightManager.getInstance(mySearchResults.getProject())
          .removeSegmentHighlighter(mySearchResults.getEditor(), myCursorHighlighter);
      myCursorHighlighter = null;
    }

    final FindResult cursor = mySearchResults.getCursor();
    Editor editor = mySearchResults.getEditor();
    SelectionModel selection = editor.getSelectionModel();
    if (cursor != null) {
      Set<RangeHighlighter> dummy = new HashSet<RangeHighlighter>();
      highlightRange(
          cursor, new TextAttributes(null, null, Color.BLACK, EffectType.ROUNDED_BOX, 0), dummy);
      if (!dummy.isEmpty()) {
        myCursorHighlighter = dummy.iterator().next();
      }

      if (scroll) {
        if (mySearchResults.getFindModel().isGlobal()) {
          FoldingModel foldingModel = editor.getFoldingModel();
          final FoldRegion[] allRegions = editor.getFoldingModel().getAllFoldRegions();

          foldingModel.runBatchFoldingOperation(
              new Runnable() {
                @Override
                public void run() {
                  for (FoldRegion region : allRegions) {
                    if (!region.isValid()) continue;
                    if (cursor.intersects(TextRange.create(region))) {
                      region.setExpanded(true);
                    }
                  }
                }
              });
          selection.setSelection(cursor.getStartOffset(), cursor.getEndOffset());

          editor.getCaretModel().moveToOffset(cursor.getEndOffset());
          editor.getScrollingModel().scrollToCaret(ScrollType.CENTER);
        } else {
          if (!SearchResults.insideVisibleArea(editor, cursor)) {
            LogicalPosition pos = editor.offsetToLogicalPosition(cursor.getStartOffset());
            editor.getScrollingModel().scrollTo(pos, ScrollType.CENTER);
          }
        }
      }
      editor
          .getScrollingModel()
          .runActionOnScrollingFinished(
              new Runnable() {
                @Override
                public void run() {
                  showReplacementPreview();
                }
              });
    }
  }
 public void startTemplateWithPrefix(
     final Editor editor,
     final TemplateImpl template,
     final int templateStart,
     @Nullable final PairProcessor<String, String> processor,
     @Nullable final String argument) {
   final int caretOffset = editor.getCaretModel().getOffset();
   final TemplateState templateState = initTemplateState(editor);
   CommandProcessor commandProcessor = CommandProcessor.getInstance();
   commandProcessor.executeCommand(
       myProject,
       () -> {
         editor.getDocument().deleteString(templateStart, caretOffset);
         editor.getCaretModel().moveToOffset(templateStart);
         editor.getScrollingModel().scrollToCaret(ScrollType.RELATIVE);
         editor.getSelectionModel().removeSelection();
         Map<String, String> predefinedVarValues = null;
         if (argument != null) {
           predefinedVarValues = new HashMap<String, String>();
           predefinedVarValues.put(TemplateImpl.ARG, argument);
         }
         templateState.start(template, processor, predefinedVarValues);
       },
       CodeInsightBundle.message("insert.code.template.command"),
       null);
 }
  private void removeFromEditor() {
    Editor editor = mySearchResults.getEditor();
    if (myReplacementBalloon != null) {
      myReplacementBalloon.hide();
    }

    if (editor != null) {

      for (VisibleAreaListener visibleAreaListener : myVisibleAreaListenersToRemove) {
        editor.getScrollingModel().removeVisibleAreaListener(visibleAreaListener);
      }
      myVisibleAreaListenersToRemove.clear();
      Project project = mySearchResults.getProject();
      if (project != null && !project.isDisposed()) {
        for (RangeHighlighter h : myHighlighters) {
          HighlightManager.getInstance(project).removeSegmentHighlighter(editor, h);
        }
        if (myCursorHighlighter != null) {
          HighlightManager.getInstance(project)
              .removeSegmentHighlighter(editor, myCursorHighlighter);
          myCursorHighlighter = null;
        }
      }
      myHighlighters.clear();
      if (myListeningSelection) {
        editor.getSelectionModel().removeSelectionListener(this);
        myListeningSelection = false;
      }
    }
  }
  private void altCommitToOriginal(@NotNull DocumentEvent e) {
    final PsiFile origPsiFile =
        PsiDocumentManager.getInstance(myProject).getPsiFile(myOrigDocument);
    String newText = myNewDocument.getText();
    // prepare guarded blocks
    LinkedHashMap<String, String> replacementMap = new LinkedHashMap<String, String>();
    int count = 0;
    for (RangeMarker o : ContainerUtil.reverse(((DocumentEx) myNewDocument).getGuardedBlocks())) {
      String replacement = o.getUserData(REPLACEMENT_KEY);
      String tempText = "REPLACE" + (count++) + Long.toHexString(StringHash.calc(replacement));
      newText =
          newText.substring(0, o.getStartOffset()) + tempText + newText.substring(o.getEndOffset());
      replacementMap.put(tempText, replacement);
    }
    // run preformat processors
    final int hostStartOffset = myAltFullRange.getStartOffset();
    myEditor.getCaretModel().moveToOffset(hostStartOffset);
    for (CopyPastePreProcessor preProcessor :
        Extensions.getExtensions(CopyPastePreProcessor.EP_NAME)) {
      newText = preProcessor.preprocessOnPaste(myProject, origPsiFile, myEditor, newText, null);
    }
    myOrigDocument.replaceString(hostStartOffset, myAltFullRange.getEndOffset(), newText);
    // replace temp strings for guarded blocks
    for (String tempText : replacementMap.keySet()) {
      int idx =
          CharArrayUtil.indexOf(
              myOrigDocument.getCharsSequence(),
              tempText,
              hostStartOffset,
              myAltFullRange.getEndOffset());
      myOrigDocument.replaceString(idx, idx + tempText.length(), replacementMap.get(tempText));
    }
    // JAVA: fix occasional char literal concatenation
    fixDocumentQuotes(myOrigDocument, hostStartOffset - 1);
    fixDocumentQuotes(myOrigDocument, myAltFullRange.getEndOffset());

    // reformat
    PsiDocumentManager.getInstance(myProject).commitDocument(myOrigDocument);
    Runnable task =
        () -> {
          try {
            CodeStyleManager.getInstance(myProject)
                .reformatRange(origPsiFile, hostStartOffset, myAltFullRange.getEndOffset(), true);
          } catch (IncorrectOperationException e1) {
            // LOG.error(e);
          }
        };
    DocumentUtil.executeInBulk(myOrigDocument, true, task);

    PsiElement newInjected =
        InjectedLanguageManager.getInstance(myProject)
            .findInjectedElementAt(origPsiFile, hostStartOffset);
    DocumentWindow documentWindow =
        newInjected == null ? null : InjectedLanguageUtil.getDocumentWindow(newInjected);
    if (documentWindow != null) {
      myEditor.getCaretModel().moveToOffset(documentWindow.injectedToHost(e.getOffset()));
      myEditor.getScrollingModel().scrollToCaret(ScrollType.MAKE_VISIBLE);
    }
  }
 public void nextPanel(final BeforeAfter<ShiftedSimpleContent> diff, final DiffPanel diffPanel) {
   final Editor editor1 = ((DiffPanelImpl) diffPanel).getEditor1();
   myLeftModels.add(editor1.getScrollingModel());
   final Editor editor2 = ((DiffPanelImpl) diffPanel).getEditor2();
   myRightModels.add(editor2.getScrollingModel());
   if (myEditor == null) {
     myEditor = editor1;
   }
   myLeftEditors.add(editor1);
   myRightEditors.add(editor2);
   ((EditorEx) editor1).setHorizontalScrollbarVisible(false);
   ((EditorEx) editor1).setVerticalScrollbarVisible(false);
   ((EditorEx) editor1).getScrollPane().setWheelScrollingEnabled(false);
   ((EditorEx) editor2).setHorizontalScrollbarVisible(false);
   ((EditorEx) editor2).setVerticalScrollbarVisible(false);
   ((EditorEx) editor2).getScrollPane().setWheelScrollingEnabled(false);
 }
  public static int insertStringAtCaret(
      Editor editor,
      @NotNull String s,
      boolean toProcessOverwriteMode,
      boolean toMoveCaret,
      int caretShift) {
    final SelectionModel selectionModel = editor.getSelectionModel();
    if (selectionModel.hasSelection()) {
      editor.getCaretModel().moveToOffset(selectionModel.getSelectionStart(), true);
    }

    // There is a possible case that particular soft wraps become hard wraps if the caret is located
    // at soft wrap-introduced virtual
    // space, hence, we need to give editor a chance to react accordingly.
    editor.getSoftWrapModel().beforeDocumentChangeAtCaret();
    int oldOffset = editor.getCaretModel().getOffset();

    String filler = calcStringToFillVirtualSpace(editor);
    if (filler.length() > 0) {
      s = filler + s;
    }

    Document document = editor.getDocument();
    if (editor.isInsertMode() || !toProcessOverwriteMode) {
      if (selectionModel.hasSelection()) {
        oldOffset = selectionModel.getSelectionStart();
        document.replaceString(
            selectionModel.getSelectionStart(), selectionModel.getSelectionEnd(), s);
      } else {
        document.insertString(oldOffset, s);
      }
    } else {
      deleteSelectedText(editor);
      int lineNumber = editor.getCaretModel().getLogicalPosition().line;
      if (lineNumber >= document.getLineCount()) {
        return insertStringAtCaret(editor, s, false, toMoveCaret);
      }

      int endOffset = document.getLineEndOffset(lineNumber);
      document.replaceString(oldOffset, Math.min(endOffset, oldOffset + s.length()), s);
    }

    int offset = oldOffset + filler.length() + caretShift;
    if (toMoveCaret) {
      editor.getCaretModel().moveToOffset(offset, true);
      editor.getScrollingModel().scrollToCaret(ScrollType.RELATIVE);
      selectionModel.removeSelection();
    } else if (editor.getCaretModel().getOffset()
        != oldOffset) { // handling the case when caret model tracks document changes
      editor.getCaretModel().moveToOffset(oldOffset);
    }

    return offset;
  }
  public static void deleteSelectedText(Editor editor) {
    SelectionModel selectionModel = editor.getSelectionModel();
    if (selectionModel.hasBlockSelection()) deleteBlockSelection(editor);
    if (!selectionModel.hasSelection()) return;

    int selectionStart = selectionModel.getSelectionStart();
    int selectionEnd = selectionModel.getSelectionEnd();

    editor.getCaretModel().moveToOffset(selectionStart);
    selectionModel.removeSelection();
    editor.getDocument().deleteString(selectionStart, selectionEnd);
    editor.getScrollingModel().scrollToCaret(ScrollType.RELATIVE);
  }
    @Override
    public RelativePoint recalculateLocation(final Balloon object) {
      FindResult cursor = mySearchResults.getCursor();
      if (cursor == null) return null;
      final TextRange cur = cursor;
      int startOffset = cur.getStartOffset();
      int endOffset = cur.getEndOffset();

      if (startOffset >= myEditor.getDocument().getTextLength()) {
        if (!object.isDisposed()) {
          requestBalloonHiding(object);
        }
        return null;
      }
      if (!SearchResults.insideVisibleArea(myEditor, cur)) {
        requestBalloonHiding(object);

        VisibleAreaListener visibleAreaListener =
            new VisibleAreaListener() {
              @Override
              public void visibleAreaChanged(VisibleAreaEvent e) {
                if (SearchResults.insideVisibleArea(myEditor, cur)) {
                  showReplacementPreview();
                  final VisibleAreaListener visibleAreaListener = this;
                  final boolean remove = myVisibleAreaListenersToRemove.remove(visibleAreaListener);
                  if (remove) {
                    myEditor.getScrollingModel().removeVisibleAreaListener(visibleAreaListener);
                  }
                }
              }
            };
        myEditor.getScrollingModel().addVisibleAreaListener(visibleAreaListener);
        myVisibleAreaListenersToRemove.add(visibleAreaListener);
      }

      Point startPoint = myEditor.visualPositionToXY(myEditor.offsetToVisualPosition(startOffset));
      Point endPoint = myEditor.visualPositionToXY(myEditor.offsetToVisualPosition(endOffset));
      Point point = new Point((startPoint.x + endPoint.x) / 2, startPoint.y);

      return new RelativePoint(myEditor.getContentComponent(), point);
    }
  private void insertLookupString(LookupElement item, final int prefix) {
    final String lookupString = getCaseCorrectedLookupString(item);

    final Editor hostEditor = InjectedLanguageUtil.getTopLevelEditor(myEditor);
    hostEditor
        .getCaretModel()
        .runForEachCaret(
            new CaretAction() {
              @Override
              public void perform(Caret caret) {
                EditorModificationUtil.deleteSelectedText(hostEditor);
                final int caretOffset = hostEditor.getCaretModel().getOffset();
                int lookupStart = Math.max(caretOffset - prefix, 0);

                int len = hostEditor.getDocument().getTextLength();
                LOG.assertTrue(
                    lookupStart >= 0 && lookupStart <= len,
                    "ls: "
                        + lookupStart
                        + " caret: "
                        + caretOffset
                        + " prefix:"
                        + prefix
                        + " doc: "
                        + len);
                LOG.assertTrue(
                    caretOffset >= 0 && caretOffset <= len, "co: " + caretOffset + " doc: " + len);

                hostEditor.getDocument().replaceString(lookupStart, caretOffset, lookupString);

                int offset = lookupStart + lookupString.length();
                hostEditor.getCaretModel().moveToOffset(offset);
                hostEditor.getSelectionModel().removeSelection();
              }
            });

    myEditor.getScrollingModel().scrollToCaret(ScrollType.RELATIVE);
  }
  private static Runnable rememberDocumentState(final Editor _editor) {
    final Editor editor = InjectedLanguageUtil.getTopLevelEditor(_editor);
    final String documentText = editor.getDocument().getText();
    final int caret = editor.getCaretModel().getOffset();
    final int selStart = editor.getSelectionModel().getSelectionStart();
    final int selEnd = editor.getSelectionModel().getSelectionEnd();

    final int vOffset = editor.getScrollingModel().getVerticalScrollOffset();
    final int hOffset = editor.getScrollingModel().getHorizontalScrollOffset();

    return new Runnable() {
      @Override
      public void run() {
        DocumentEx document = (DocumentEx) editor.getDocument();

        document.replaceString(0, document.getTextLength(), documentText);
        editor.getCaretModel().moveToOffset(caret);
        editor.getSelectionModel().setSelection(selStart, selEnd);

        editor.getScrollingModel().scrollHorizontally(hOffset);
        editor.getScrollingModel().scrollVertically(vOffset);
      }
    };
  }
  public static void deleteBlockSelection(Editor editor) {
    SelectionModel selectionModel = editor.getSelectionModel();
    if (!selectionModel.hasBlockSelection()) return;

    LogicalPosition blockStart = selectionModel.getBlockStart();
    LogicalPosition blockEnd = selectionModel.getBlockEnd();
    if (blockStart == null || blockEnd == null) {
      return;
    }

    int startLine = blockStart.line;
    int endLine = blockEnd.line;

    int[] starts = selectionModel.getBlockSelectionStarts();
    int[] ends = selectionModel.getBlockSelectionEnds();

    for (int i = starts.length - 1; i >= 0; i--) {
      editor.getDocument().deleteString(starts[i], ends[i]);
    }

    editor.getScrollingModel().scrollToCaret(ScrollType.RELATIVE);

    zeroWidthBlockSelectionAtCaretColumn(editor, startLine, endLine);
  }
 private static void scrollToCaret(@NotNull Editor e) {
   e.getScrollingModel().scrollToCaret(ScrollType.CENTER);
 }
    @Override
    public void run() {
      CaretModel caretModel = myEditor.getCaretModel();
      try {
        final CharSequence chars = myDocument.getCharsSequence();
        int i = CharArrayUtil.shiftBackwardUntil(chars, myOffset - 1, LINE_SEPARATOR) - 1;
        i = CharArrayUtil.shiftBackwardUntil(chars, i, LINE_SEPARATOR) + 1;
        if (i < 0) i = 0;
        int lineStart = CharArrayUtil.shiftForward(chars, i, " \t");
        CodeDocumentationUtil.CommentContext commentContext =
            CodeDocumentationUtil.tryParseCommentContext(myFile, chars, myOffset, lineStart);

        PsiDocumentManager psiDocumentManager = PsiDocumentManager.getInstance(getProject());
        if (commentContext.docStart) {
          PsiElement element = myFile.findElementAt(commentContext.lineStart);
          final String text = element.getText();
          final PsiElement parent = element.getParent();

          if (text.equals(commentContext.commenter.getDocumentationCommentPrefix())
                  && isDocComment(parent, commentContext.commenter)
              || text.startsWith(commentContext.commenter.getDocumentationCommentPrefix())
                  && element instanceof PsiComment) {
            PsiComment comment =
                isDocComment(parent, commentContext.commenter)
                    ? (PsiComment) parent
                    : (PsiComment) element;
            int commentEnd = comment.getTextRange().getEndOffset();

            if (myOffset >= commentEnd) {
              commentContext.docStart = false;
            } else {
              if (isCommentComplete(comment, commentContext.commenter, myEditor)) {
                if (myOffset >= commentEnd) {
                  commentContext.docAsterisk = false;
                  commentContext.docStart = false;
                } else {
                  commentContext.docAsterisk = true;
                  commentContext.docStart = false;
                }
              } else {
                generateJavadoc(commentContext.commenter);
              }
            }
          } else {
            commentContext.docStart = false;
          }
        } else if (commentContext.cStyleStart) {
          PsiElement element = myFile.findElementAt(commentContext.lineStart);
          if (element instanceof PsiComment
              && commentContext.commenter.getBlockCommentTokenType()
                  == ((PsiComment) element).getTokenType()) {
            final PsiComment comment = (PsiComment) element;
            int commentEnd = comment.getTextRange().getEndOffset();
            if (myOffset >= commentEnd && myOffset < myFile.getTextRange().getEndOffset()) {
              commentContext.docStart = false;
            } else {
              if (isCommentComplete(comment, commentContext.commenter, myEditor)) {
                if (myOffset >= commentEnd) {
                  commentContext.docAsterisk = false;
                  commentContext.docStart = false;
                } else {
                  commentContext.docAsterisk = true;
                  commentContext.docStart = false;
                }
              } else {
                final int currentEndOfLine = CharArrayUtil.shiftForwardUntil(chars, myOffset, "\n");
                myDocument.insertString(
                    currentEndOfLine, " " + commentContext.commenter.getBlockCommentSuffix());
                int lstart = CharArrayUtil.shiftBackwardUntil(chars, myOffset, "\n");
                myDocument.insertString(currentEndOfLine, chars.subSequence(lstart, myOffset));
                psiDocumentManager.commitDocument(myDocument);
              }
            }
          } else {
            commentContext.docStart = false;
          }
        }

        String indentInsideJavadoc = null;
        if (myOffset < myDocument.getTextLength()) {
          final int line = myDocument.getLineNumber(myOffset);
          if (line > 0 && (commentContext.docAsterisk || commentContext.docStart)) {
            indentInsideJavadoc =
                CodeDocumentationUtil.getIndentInsideJavadoc(
                    myDocument, myDocument.getLineStartOffset(line - 1));
          }
        }

        if (commentContext.docAsterisk) {
          commentContext.docAsterisk =
              insertDocAsterisk(
                  commentContext.lineStart,
                  commentContext.docAsterisk,
                  !StringUtil.isEmpty(indentInsideJavadoc),
                  commentContext.commenter);
        }

        boolean docIndentApplied = false;
        CodeInsightSettings codeInsightSettings = CodeInsightSettings.getInstance();
        if (codeInsightSettings.SMART_INDENT_ON_ENTER
            || myForceIndent
            || commentContext.docStart
            || commentContext.docAsterisk
            || commentContext.slashSlash) {
          final CodeStyleManager codeStyleManager = CodeStyleManager.getInstance(getProject());
          myOffset = codeStyleManager.adjustLineIndent(myFile, myOffset);
          psiDocumentManager.commitAllDocuments();

          if (!StringUtil.isEmpty(indentInsideJavadoc) && myOffset < myDocument.getTextLength()) {
            myDocument.insertString(myOffset + 1, indentInsideJavadoc);
            myOffset += indentInsideJavadoc.length();
            docIndentApplied = true;
          }

          if (myForceIndent && indentInsideJavadoc != null) {
            int indentSize =
                CodeStyleSettingsManager.getSettings(myProject).getIndentSize(myFile.getFileType());
            myDocument.insertString(myOffset + 1, StringUtil.repeatSymbol(' ', indentSize));
            myCaretAdvance += indentSize;
          }
        }

        if ((commentContext.docAsterisk || commentContext.docStart || commentContext.slashSlash)
            && !docIndentApplied) {
          if (myInsertSpace) {
            if (myOffset == myDocument.getTextLength()) {
              myDocument.insertString(myOffset, " ");
            }
            myDocument.insertString(myOffset + 1, " ");
          }

          final char c = myDocument.getCharsSequence().charAt(myOffset);
          if (c != '\n') {
            myOffset += 1;
          }
        }

        if ((commentContext.docAsterisk || commentContext.slashSlash) && !commentContext.docStart) {
          myCaretAdvance +=
              commentContext.slashSlash
                  ? commentContext.commenter.getLineCommentPrefix().length()
                  : 1;
        }
      } catch (IncorrectOperationException e) {
        LOG.error(e);
      }

      myOffset = Math.min(myOffset, myDocument.getTextLength());
      caretModel.moveToOffset(myOffset);
      myEditor.getScrollingModel().scrollToCaret(ScrollType.RELATIVE);
      myEditor.getSelectionModel().removeSelection();
      if (myCaretAdvance != 0) {
        LogicalPosition caretPosition = caretModel.getLogicalPosition();
        LogicalPosition pos =
            new LogicalPosition(caretPosition.line, caretPosition.column + myCaretAdvance);
        caretModel.moveToLogicalPosition(pos);
      }
    }
Example #16
0
  private static void doPaste(
      final Editor editor,
      final Project project,
      final PsiFile file,
      final Document document,
      final Producer<Transferable> producer) {
    Transferable content = null;

    if (producer != null) {
      content = producer.produce();
    } else {
      CopyPasteManager manager = CopyPasteManager.getInstance();
      if (manager.areDataFlavorsAvailable(DataFlavor.stringFlavor)) {
        content = manager.getContents();
        if (content != null) {
          manager.stopKillRings();
        }
      }
    }

    if (content != null) {
      String text = null;
      try {
        text = (String) content.getTransferData(DataFlavor.stringFlavor);
      } catch (Exception e) {
        editor.getComponent().getToolkit().beep();
      }
      if (text == null) return;

      final CodeInsightSettings settings = CodeInsightSettings.getInstance();

      final Map<CopyPastePostProcessor, TextBlockTransferableData> extraData =
          new HashMap<CopyPastePostProcessor, TextBlockTransferableData>();
      for (CopyPastePostProcessor processor :
          Extensions.getExtensions(CopyPastePostProcessor.EP_NAME)) {
        TextBlockTransferableData data = processor.extractTransferableData(content);
        if (data != null) {
          extraData.put(processor, data);
        }
      }

      text = TextBlockTransferable.convertLineSeparators(text, "\n", extraData.values());

      final CaretModel caretModel = editor.getCaretModel();
      final SelectionModel selectionModel = editor.getSelectionModel();
      final int col = caretModel.getLogicalPosition().column;

      // There is a possible case that we want to perform paste while there is an active selection
      // at the editor and caret is located
      // inside it (e.g. Ctrl+A is pressed while caret is not at the zero column). We want to insert
      // the text at selection start column
      // then, hence, inserted block of text should be indented according to the selection start as
      // well.
      final int blockIndentAnchorColumn;
      final int caretOffset = caretModel.getOffset();
      if (selectionModel.hasSelection() && caretOffset >= selectionModel.getSelectionStart()) {
        blockIndentAnchorColumn =
            editor.offsetToLogicalPosition(selectionModel.getSelectionStart()).column;
      } else {
        blockIndentAnchorColumn = col;
      }

      // We assume that EditorModificationUtil.insertStringAtCaret() is smart enough to remove
      // currently selected text (if any).

      RawText rawText = RawText.fromTransferable(content);
      String newText = text;
      for (CopyPastePreProcessor preProcessor :
          Extensions.getExtensions(CopyPastePreProcessor.EP_NAME)) {
        newText = preProcessor.preprocessOnPaste(project, file, editor, newText, rawText);
      }
      int indentOptions =
          text.equals(newText) ? settings.REFORMAT_ON_PASTE : CodeInsightSettings.REFORMAT_BLOCK;
      text = newText;

      if (LanguageFormatting.INSTANCE.forContext(file) == null
          && indentOptions != CodeInsightSettings.NO_REFORMAT) {
        indentOptions = CodeInsightSettings.INDENT_BLOCK;
      }

      final String _text = text;
      ApplicationManager.getApplication()
          .runWriteAction(
              new Runnable() {
                @Override
                public void run() {
                  EditorModificationUtil.insertStringAtCaret(editor, _text, false, true);
                }
              });

      int length = text.length();
      int offset = caretModel.getOffset() - length;
      if (offset < 0) {
        length += offset;
        offset = 0;
      }
      final RangeMarker bounds = document.createRangeMarker(offset, offset + length);

      caretModel.moveToOffset(bounds.getEndOffset());
      editor.getScrollingModel().scrollToCaret(ScrollType.RELATIVE);
      selectionModel.removeSelection();

      final Ref<Boolean> indented = new Ref<Boolean>(Boolean.FALSE);
      for (Map.Entry<CopyPastePostProcessor, TextBlockTransferableData> e : extraData.entrySet()) {
        //noinspection unchecked
        e.getKey()
            .processTransferableData(project, editor, bounds, caretOffset, indented, e.getValue());
      }

      boolean pastedTextContainsWhiteSpacesOnly =
          CharArrayUtil.shiftForward(document.getCharsSequence(), bounds.getStartOffset(), " \n\t")
              >= bounds.getEndOffset();

      VirtualFile virtualFile = file.getVirtualFile();
      if (!pastedTextContainsWhiteSpacesOnly
          && (virtualFile == null
              || !SingleRootFileViewProvider.isTooLargeForIntelligence(virtualFile))) {
        final int indentOptions1 = indentOptions;
        ApplicationManager.getApplication()
            .runWriteAction(
                new Runnable() {
                  @Override
                  public void run() {
                    switch (indentOptions1) {
                      case CodeInsightSettings.INDENT_BLOCK:
                        if (!indented.get()) {
                          indentBlock(
                              project,
                              editor,
                              bounds.getStartOffset(),
                              bounds.getEndOffset(),
                              blockIndentAnchorColumn);
                        }
                        break;

                      case CodeInsightSettings.INDENT_EACH_LINE:
                        if (!indented.get()) {
                          indentEachLine(
                              project, editor, bounds.getStartOffset(), bounds.getEndOffset());
                        }
                        break;

                      case CodeInsightSettings.REFORMAT_BLOCK:
                        indentEachLine(
                            project,
                            editor,
                            bounds.getStartOffset(),
                            bounds
                                .getEndOffset()); // this is needed for example when inserting a
                                                  // comment before method
                        reformatBlock(
                            project, editor, bounds.getStartOffset(), bounds.getEndOffset());
                        break;
                    }
                  }
                });
      }

      if (bounds.isValid()) {
        caretModel.moveToOffset(bounds.getEndOffset());
        editor.getScrollingModel().scrollToCaret(ScrollType.RELATIVE);
        selectionModel.removeSelection();
        editor.putUserData(EditorEx.LAST_PASTED_REGION, TextRange.create(bounds));
      }
    }
  }
  public final void move(Editor editor, final PsiFile file) {
    myMover.beforeMove(editor, myInfo, myIsDown);
    final Document document = editor.getDocument();
    final int start =
        StatementUpDownMover.getLineStartSafeOffset(document, myInfo.toMove.startLine);
    final int end = StatementUpDownMover.getLineStartSafeOffset(document, myInfo.toMove.endLine);
    myInfo.range1 = document.createRangeMarker(start, end);

    String textToInsert = document.getCharsSequence().subSequence(start, end).toString();
    if (!StringUtil.endsWithChar(textToInsert, '\n')) textToInsert += '\n';

    final int start2 = document.getLineStartOffset(myInfo.toMove2.startLine);
    final int end2 = StatementUpDownMover.getLineStartSafeOffset(document, myInfo.toMove2.endLine);
    String textToInsert2 = document.getCharsSequence().subSequence(start2, end2).toString();
    if (!StringUtil.endsWithChar(textToInsert2, '\n')) textToInsert2 += '\n';
    myInfo.range2 = document.createRangeMarker(start2, end2);
    if (myInfo.range1.getStartOffset() < myInfo.range2.getStartOffset()) {
      myInfo.range1.setGreedyToLeft(true);
      myInfo.range1.setGreedyToRight(false);
      myInfo.range2.setGreedyToLeft(true);
      myInfo.range2.setGreedyToRight(true);
    } else {
      myInfo.range1.setGreedyToLeft(true);
      myInfo.range1.setGreedyToRight(true);
      myInfo.range2.setGreedyToLeft(true);
      myInfo.range2.setGreedyToRight(false);
    }

    final CaretModel caretModel = editor.getCaretModel();
    final int caretRelativePos = caretModel.getOffset() - start;
    final SelectionModel selectionModel = editor.getSelectionModel();
    final int selectionStart = selectionModel.getSelectionStart();
    final int selectionEnd = selectionModel.getSelectionEnd();
    final boolean hasSelection = selectionModel.hasSelection();

    // to prevent flicker
    caretModel.moveToOffset(0);

    // There is a possible case that the user performs, say, method move. It's also possible that
    // one (or both) of moved methods
    // are folded. We want to preserve their states then. The problem is that folding processing is
    // based on PSI element pointers
    // and the pointers behave as following during move up/down:
    //     method1() {}
    //     method2() {}
    // Pointer for the fold region from method1 points to 'method2()' now and vice versa (check
    // range markers processing on
    // document change for further information). I.e. information about fold regions statuses holds
    // the data swapped for
    // 'method1' and 'method2'. Hence, we want to apply correct 'collapsed' status.
    FoldRegion topRegion = null;
    FoldRegion bottomRegion = null;
    for (FoldRegion foldRegion : editor.getFoldingModel().getAllFoldRegions()) {
      if (!foldRegion.isValid()
          || (!contains(myInfo.range1, foldRegion) && !contains(myInfo.range2, foldRegion))) {
        continue;
      }
      if (contains(myInfo.range1, foldRegion) && !contains(topRegion, foldRegion)) {
        topRegion = foldRegion;
      } else if (contains(myInfo.range2, foldRegion) && !contains(bottomRegion, foldRegion)) {
        bottomRegion = foldRegion;
      }
    }

    document.insertString(myInfo.range1.getStartOffset(), textToInsert2);
    document.deleteString(
        myInfo.range1.getStartOffset() + textToInsert2.length(), myInfo.range1.getEndOffset());

    document.insertString(myInfo.range2.getStartOffset(), textToInsert);
    int s = myInfo.range2.getStartOffset() + textToInsert.length();
    int e = myInfo.range2.getEndOffset();
    if (e > s) {
      document.deleteString(s, e);
    }

    final Project project = file.getProject();
    PsiDocumentManager.getInstance(project).commitAllDocuments();

    // Swap fold regions status if necessary.
    if (topRegion != null && bottomRegion != null) {
      final FoldRegion finalTopRegion = topRegion;
      final FoldRegion finalBottomRegion = bottomRegion;
      editor
          .getFoldingModel()
          .runBatchFoldingOperation(
              new Runnable() {
                @Override
                public void run() {
                  boolean topExpanded = finalTopRegion.isExpanded();
                  finalTopRegion.setExpanded(finalBottomRegion.isExpanded());
                  finalBottomRegion.setExpanded(topExpanded);
                }
              });
    }
    CodeFoldingManager.getInstance(project).allowFoldingOnCaretLine(editor);

    if (hasSelection) {
      restoreSelection(editor, selectionStart, selectionEnd, start, myInfo.range2.getStartOffset());
    }

    caretModel.moveToOffset(myInfo.range2.getStartOffset() + caretRelativePos);
    if (myInfo.indentTarget) {
      indentLinesIn(editor, file, document, project, myInfo.range2);
    }
    if (myInfo.indentSource) {
      indentLinesIn(editor, file, document, project, myInfo.range1);
    }

    myMover.afterMove(editor, file, myInfo, myIsDown);
    editor.getScrollingModel().scrollToCaret(ScrollType.RELATIVE);
  }
 public void add(final Splitter splitter, final Editor editor) {
   editor
       .getScrollingModel()
       .addVisibleAreaListener(new MyVisibleAreaListener(mySplitters.size()));
   mySplitters.add(splitter);
 }
 public void navigate(int injectedOffset) {
   if (myAction.isShowInBalloon()) {
     final JComponent component = myAction.createBalloonComponent(myNewFile);
     if (component != null) {
       final Balloon balloon =
           JBPopupFactory.getInstance()
               .createBalloonBuilder(component)
               .setShadow(true)
               .setAnimationCycle(0)
               .setHideOnClickOutside(true)
               .setHideOnKeyOutside(true)
               .setHideOnAction(false)
               .setFillColor(UIUtil.getControlColor())
               .createBalloon();
       new AnAction() {
         @Override
         public void actionPerformed(AnActionEvent e) {
           balloon.hide();
         }
       }.registerCustomShortcutSet(CommonShortcuts.ESCAPE, component);
       Disposer.register(myNewFile.getProject(), balloon);
       final Balloon.Position position = QuickEditAction.getBalloonPosition(myEditor);
       RelativePoint point = JBPopupFactory.getInstance().guessBestPopupLocation(myEditor);
       if (position == Balloon.Position.above) {
         final Point p = point.getPoint();
         point =
             new RelativePoint(
                 point.getComponent(), new Point(p.x, p.y - myEditor.getLineHeight()));
       }
       balloon.show(point, position);
     }
   } else {
     final FileEditorManagerEx fileEditorManager = FileEditorManagerEx.getInstanceEx(myProject);
     final FileEditor[] editors = fileEditorManager.getEditors(myNewVirtualFile);
     if (editors.length == 0) {
       final EditorWindow curWindow = fileEditorManager.getCurrentWindow();
       mySplittedWindow =
           curWindow.split(SwingConstants.HORIZONTAL, false, myNewVirtualFile, true);
     }
     Editor editor =
         fileEditorManager.openTextEditor(
             new OpenFileDescriptor(myProject, myNewVirtualFile, injectedOffset), true);
     // fold missing values
     if (editor != null) {
       editor.putUserData(QuickEditAction.QUICK_EDIT_HANDLER, this);
       final FoldingModel foldingModel = editor.getFoldingModel();
       foldingModel.runBatchFoldingOperation(
           () -> {
             for (RangeMarker o :
                 ContainerUtil.reverse(((DocumentEx) myNewDocument).getGuardedBlocks())) {
               String replacement = o.getUserData(REPLACEMENT_KEY);
               if (StringUtil.isEmpty(replacement)) continue;
               FoldRegion region =
                   foldingModel.addFoldRegion(o.getStartOffset(), o.getEndOffset(), replacement);
               if (region != null) region.setExpanded(false);
             }
           });
     }
     SwingUtilities.invokeLater(
         () -> myEditor.getScrollingModel().scrollToCaret(ScrollType.MAKE_VISIBLE));
   }
 }
  public void invoke(@NotNull Project project, @NotNull Editor editor, @NotNull PsiFile file) {
    myProject = project;
    myFile = file.getViewProvider().getPsi(file.getViewProvider().getBaseLanguage());
    myEditor = editor;

    PsiElement context = myFile.getContext();

    if (context != null && (context.textContains('\'') || context.textContains('\"'))) {
      String s = context.getText();
      if (StringUtil.startsWith(s, "\"") || StringUtil.startsWith(s, "\'")) {
        myFile = context.getContainingFile();
        myEditor = editor instanceof EditorWindow ? ((EditorWindow) editor).getDelegate() : editor;
      }
    }

    myDocument = myEditor.getDocument();
    if (!FileDocumentManager.getInstance().requestWriting(myDocument, project)) {
      return;
    }

    PsiDocumentManager.getInstance(project).commitDocument(myDocument);

    FeatureUsageTracker.getInstance().triggerFeatureUsed("codeassists.comment.line");

    myCodeStyleManager = CodeStyleManager.getInstance(myProject);

    final SelectionModel selectionModel = myEditor.getSelectionModel();

    boolean hasSelection = selectionModel.hasSelection();
    myStartOffset = selectionModel.getSelectionStart();
    myEndOffset = selectionModel.getSelectionEnd();

    FoldRegion fold = myEditor.getFoldingModel().getCollapsedRegionAtOffset(myStartOffset);
    if (fold != null
        && fold.shouldNeverExpand()
        && fold.getStartOffset() == myStartOffset
        && fold.getEndOffset() == myEndOffset) {
      // Foldings that never expand are automatically selected, so the fact it is selected must not
      // interfer with commenter's logic
      hasSelection = false;
    }

    if (myDocument.getTextLength() == 0) return;

    while (true) {
      int lastLineEnd = myDocument.getLineEndOffset(myDocument.getLineNumber(myEndOffset));
      FoldRegion collapsedAt = myEditor.getFoldingModel().getCollapsedRegionAtOffset(lastLineEnd);
      if (collapsedAt != null) {
        final int endOffset = collapsedAt.getEndOffset();
        if (endOffset <= myEndOffset) {
          break;
        }
        myEndOffset = endOffset;
      } else {
        break;
      }
    }

    boolean wholeLinesSelected =
        !hasSelection
            || myStartOffset
                    == myDocument.getLineStartOffset(myDocument.getLineNumber(myStartOffset))
                && myEndOffset
                    == myDocument.getLineEndOffset(myDocument.getLineNumber(myEndOffset - 1)) + 1;

    boolean startingNewLineComment =
        !hasSelection
            && isLineEmpty(myDocument.getLineNumber(myStartOffset))
            && !Comparing.equal(
                IdeActions.ACTION_COMMENT_LINE,
                ActionManagerEx.getInstanceEx().getPrevPreformedActionId());
    doComment();

    if (startingNewLineComment) {
      final Commenter commenter = myCommenters[0];
      if (commenter != null) {
        String prefix;
        if (commenter instanceof SelfManagingCommenter) {
          prefix =
              ((SelfManagingCommenter) commenter)
                  .getCommentPrefix(
                      myStartLine,
                      myDocument,
                      myCommenterStateMap.get((SelfManagingCommenter) commenter));
          if (prefix == null) prefix = ""; // TODO
        } else {
          prefix = commenter.getLineCommentPrefix();
          if (prefix == null) prefix = commenter.getBlockCommentPrefix();
        }

        int lineStart = myDocument.getLineStartOffset(myStartLine);
        lineStart = CharArrayUtil.shiftForward(myDocument.getCharsSequence(), lineStart, " \t");
        lineStart += prefix.length();
        lineStart = CharArrayUtil.shiftForward(myDocument.getCharsSequence(), lineStart, " \t");
        if (lineStart > myDocument.getTextLength()) lineStart = myDocument.getTextLength();
        myEditor.getCaretModel().moveToOffset(lineStart);
        myEditor.getScrollingModel().scrollToCaret(ScrollType.RELATIVE);
      }
    } else {
      if (!hasSelection) {
        // Don't tweak caret position if we're already located on the last document line.
        LogicalPosition position = myEditor.getCaretModel().getLogicalPosition();
        if (position.line < myDocument.getLineCount() - 1) {
          int verticalShift =
              1
                  + myEditor.getSoftWrapModel().getSoftWrapsForLine(position.line).size()
                  - position.softWrapLinesOnCurrentLogicalLine;
          myEditor.getCaretModel().moveCaretRelatively(0, verticalShift, false, false, true);
        }
      } else {
        if (wholeLinesSelected) {
          selectionModel.setSelection(myStartOffset, selectionModel.getSelectionEnd());
        }
      }
    }
  }