public static void deleteToTargetPosition(@NotNull Editor editor, @NotNull LogicalPosition pos) {
   LogicalPosition logicalPosition = editor.getCaretModel().getLogicalPosition();
   if (logicalPosition.line != pos.line) {
     LOGGER.error(
         "Unexpected caret position: " + logicalPosition + ", target indent position: " + pos);
     return;
   }
   if (pos.column < logicalPosition.column) {
     int targetOffset = editor.logicalPositionToOffset(pos);
     int offset = editor.getCaretModel().getOffset();
     editor.getSelectionModel().setSelection(targetOffset, offset);
     EditorModificationUtil.deleteSelectedText(editor);
   } else if (pos.column > logicalPosition.column) {
     EditorModificationUtil.insertStringAtCaret(
         editor, StringUtil.repeatSymbol(' ', pos.column - logicalPosition.column));
   }
 }
  @Override
  public TextRange surroundStatements(
      Project project, Editor editor, PsiElement container, PsiElement[] statements)
      throws IncorrectOperationException {
    PsiManager manager = PsiManager.getInstance(project);
    PsiElementFactory factory = JavaPsiFacade.getInstance(manager.getProject()).getElementFactory();
    CodeStyleManager codeStyleManager = CodeStyleManager.getInstance(project);

    statements = SurroundWithUtil.moveDeclarationsOut(container, statements, false);
    if (statements.length == 0) {
      return null;
    }

    @NonNls String text = "try{\n}finally{\n\n}";
    PsiTryStatement tryStatement = (PsiTryStatement) factory.createStatementFromText(text, null);
    tryStatement = (PsiTryStatement) codeStyleManager.reformat(tryStatement);

    tryStatement =
        (PsiTryStatement) container.addAfter(tryStatement, statements[statements.length - 1]);

    PsiCodeBlock tryBlock = tryStatement.getTryBlock();
    if (tryBlock == null) {
      return null;
    }
    SurroundWithUtil.indentCommentIfNecessary(tryBlock, statements);
    tryBlock.addRange(statements[0], statements[statements.length - 1]);
    container.deleteChildRange(statements[0], statements[statements.length - 1]);

    PsiCodeBlock finallyBlock = tryStatement.getFinallyBlock();
    if (finallyBlock == null) {
      return null;
    }
    int offset = finallyBlock.getTextRange().getStartOffset() + 2;
    editor.getCaretModel().moveToOffset(offset);
    final Document document = editor.getDocument();
    PsiDocumentManager.getInstance(project).doPostponedOperationsAndUnblockDocument(document);
    editor.getSelectionModel().removeSelection();
    final PsiStatement firstTryStmt = tryBlock.getStatements()[0];
    final int indent =
        firstTryStmt.getTextOffset()
            - document.getLineStartOffset(document.getLineNumber(firstTryStmt.getTextOffset()));
    EditorModificationUtil.insertStringAtCaret(editor, StringUtil.repeat(" ", indent), false, true);
    return new TextRange(editor.getCaretModel().getOffset(), editor.getCaretModel().getOffset());
  }
  private void startTemplate(
      final Editor editor,
      final String selectionString,
      final Template template,
      boolean inSeparateCommand,
      TemplateEditingListener listener,
      final PairProcessor<String, String> processor,
      final Map<String, String> predefinedVarValues) {
    final TemplateState templateState = initTemplateState(editor);

    //noinspection unchecked
    templateState.getProperties().put(ExpressionContext.SELECTION, selectionString);

    if (listener != null) {
      templateState.addTemplateStateListener(listener);
    }
    Runnable r =
        () -> {
          if (selectionString != null) {
            ApplicationManager.getApplication()
                .runWriteAction(() -> EditorModificationUtil.deleteSelectedText(editor));
          } else {
            editor.getSelectionModel().removeSelection();
          }
          templateState.start((TemplateImpl) template, processor, predefinedVarValues);
        };
    if (inSeparateCommand) {
      CommandProcessor.getInstance()
          .executeCommand(
              myProject, r, CodeInsightBundle.message("insert.code.template.command"), null);
    } else {
      r.run();
    }

    if (shouldSkipInTests()) {
      if (!templateState.isFinished()) templateState.gotoEnd(false);
    }
  }
    @Override
    public void execute(
        @NotNull final Editor editor, char charTyped, @NotNull DataContext dataContext) {
      if (editor.isViewer()) return;

      Document doc = editor.getDocument();
      Project project = CommonDataKeys.PROJECT.getData(dataContext);
      if (!FileDocumentManager.getInstance().requestWriting(doc, project)) {
        return;
      }

      doc.startGuardedBlockChecking();
      try {
        final String str = String.valueOf(charTyped);
        CommandProcessor.getInstance()
            .setCurrentCommandName(EditorBundle.message("typing.in.editor.command.name"));
        EditorModificationUtil.typeInStringAtCaretHonorMultipleCarets(editor, str, true);
      } catch (ReadOnlyFragmentModificationException e) {
        EditorActionManager.getInstance().getReadonlyFragmentModificationHandler(doc).handle(e);
      } finally {
        doc.stopGuardedBlockChecking();
      }
    }
  private void executeWriteActionInner(Editor editor, DataContext dataContext, Project project) {
    CodeInsightSettings settings = CodeInsightSettings.getInstance();
    if (project == null) {
      myOriginalHandler.execute(editor, dataContext);
      return;
    }
    final Document document = editor.getDocument();
    final PsiFile file = PsiUtilBase.getPsiFileInEditor(editor, project);

    if (file == null) {
      myOriginalHandler.execute(editor, dataContext);
      return;
    }

    CommandProcessor.getInstance()
        .setCurrentCommandName(CodeInsightBundle.message("command.name.typing"));

    EditorModificationUtil.deleteSelectedText(editor);

    int caretOffset = editor.getCaretModel().getOffset();
    CharSequence text = document.getCharsSequence();
    int length = document.getTextLength();
    if (caretOffset < length && text.charAt(caretOffset) != '\n') {
      int offset1 = CharArrayUtil.shiftBackward(text, caretOffset, " \t");
      if (offset1 < 0 || text.charAt(offset1) == '\n') {
        int offset2 = CharArrayUtil.shiftForward(text, offset1 + 1, " \t");
        boolean isEmptyLine = offset2 >= length || text.charAt(offset2) == '\n';
        if (!isEmptyLine) { // we are in leading spaces of a non-empty line
          myOriginalHandler.execute(editor, dataContext);
          return;
        }
      }
    }

    final PsiDocumentManager documentManager = PsiDocumentManager.getInstance(project);
    documentManager.commitDocument(document);

    boolean forceIndent = false;
    boolean forceSkipIndent = false;
    Ref<Integer> caretOffsetRef = new Ref<Integer>(caretOffset);
    Ref<Integer> caretAdvanceRef = new Ref<Integer>(0);

    final EnterHandlerDelegate[] delegates = Extensions.getExtensions(EnterHandlerDelegate.EP_NAME);
    for (EnterHandlerDelegate delegate : delegates) {
      EnterHandlerDelegate.Result result =
          delegate.preprocessEnter(
              file, editor, caretOffsetRef, caretAdvanceRef, dataContext, myOriginalHandler);
      if (caretOffsetRef.get() > document.getTextLength()) {
        throw new AssertionError("Wrong caret offset change by " + delegate);
      }

      if (result == EnterHandlerDelegate.Result.Stop) {
        return;
      }
      if (result != EnterHandlerDelegate.Result.Continue) {
        if (result == EnterHandlerDelegate.Result.DefaultForceIndent) {
          forceIndent = true;
        } else if (result == EnterHandlerDelegate.Result.DefaultSkipIndent) {
          forceSkipIndent = true;
        }
        break;
      }
    }

    text = document.getCharsSequence(); // update after changes done in preprocessEnter()
    caretOffset = caretOffsetRef.get().intValue();
    boolean isFirstColumn = caretOffset == 0 || text.charAt(caretOffset - 1) == '\n';
    final boolean insertSpace =
        !isFirstColumn
            && !(caretOffset >= text.length()
                || text.charAt(caretOffset) == ' '
                || text.charAt(caretOffset) == '\t');
    editor.getCaretModel().moveToOffset(caretOffset);
    myOriginalHandler.execute(editor, dataContext);
    if (!editor.isInsertMode() || forceSkipIndent) {
      return;
    }

    if (settings.SMART_INDENT_ON_ENTER || forceIndent) {
      caretOffset += 1;
      caretOffset =
          CharArrayUtil.shiftForward(editor.getDocument().getCharsSequence(), caretOffset, " \t");
    } else {
      caretOffset = editor.getCaretModel().getOffset();
    }

    documentManager.commitAllDocuments();
    final DoEnterAction action =
        new DoEnterAction(
            file,
            editor,
            document,
            dataContext,
            caretOffset,
            !insertSpace,
            caretAdvanceRef.get(),
            project);
    action.setForceIndent(forceIndent);
    action.run();
    documentManager.commitDocument(document);
    for (EnterHandlerDelegate delegate : delegates) {
      if (delegate.postProcessEnter(file, editor, dataContext)
          == EnterHandlerDelegate.Result.Stop) {
        break;
      }
    }
    documentManager.commitDocument(document);
  }
  public void moveCaretRelatively(
      int columnShift,
      int lineShift,
      boolean withSelection,
      boolean blockSelection,
      boolean scrollToCaret) {
    assertIsDispatchThread();
    SelectionModel selectionModel = myEditor.getSelectionModel();
    int selectionStart = selectionModel.getLeadSelectionOffset();
    LogicalPosition blockSelectionStart =
        selectionModel.hasBlockSelection() ? selectionModel.getBlockStart() : getLogicalPosition();
    EditorSettings editorSettings = myEditor.getSettings();
    VisualPosition visualCaret = getVisualPosition();

    int desiredX = myDesiredX;
    if (columnShift == 0) {
      if (myDesiredX < 0) {
        desiredX = myEditor.visualPositionToXY(visualCaret).x;
      }
    } else {
      myDesiredX = desiredX = -1;
    }

    int newLineNumber = visualCaret.line + lineShift;
    int newColumnNumber = visualCaret.column + columnShift;
    if (desiredX >= 0 && !ApplicationManager.getApplication().isUnitTestMode()) {
      newColumnNumber =
          myEditor.xyToVisualPosition(
                  new Point(desiredX, Math.max(0, newLineNumber) * myEditor.getLineHeight()))
              .column;
    }

    Document document = myEditor.getDocument();
    if (!editorSettings.isVirtualSpace()
        && columnShift == 0
        && getLogicalPosition().softWrapLinesOnCurrentLogicalLine <= 0) {
      newColumnNumber = myEditor.getLastColumnNumber();
    } else if (!editorSettings.isVirtualSpace() && lineShift == 0 && columnShift == 1) {
      int lastLine = document.getLineCount() - 1;
      if (lastLine < 0) lastLine = 0;
      if (EditorModificationUtil.calcAfterLineEnd(myEditor) >= 0
          && newLineNumber
              < myEditor.logicalToVisualPosition(new LogicalPosition(lastLine, 0)).line) {
        newColumnNumber = 0;
        newLineNumber++;
      }
    } else if (!editorSettings.isVirtualSpace() && lineShift == 0 && columnShift == -1) {
      if (newColumnNumber < 0 && newLineNumber > 0) {
        newLineNumber--;
        newColumnNumber = EditorUtil.getLastVisualLineColumnNumber(myEditor, newLineNumber);
      }
    }

    if (newColumnNumber < 0) newColumnNumber = 0;

    // There is a possible case that caret is located at the first line and user presses 'Shift+Up'.
    // We want to select all text
    // from the document start to the current caret position then. So, we have a dedicated flag for
    // tracking that.
    boolean selectToDocumentStart = false;
    if (newLineNumber < 0) {
      selectToDocumentStart = true;
      newLineNumber = 0;

      // We want to move caret to the first column if it's already located at the first line and
      // 'Up' is pressed.
      newColumnNumber = 0;
      desiredX = -1;
    }

    VisualPosition pos = new VisualPosition(newLineNumber, newColumnNumber);
    int lastColumnNumber = newColumnNumber;
    if (!editorSettings.isCaretInsideTabs() && !myEditor.getSoftWrapModel().isInsideSoftWrap(pos)) {
      LogicalPosition log =
          myEditor.visualToLogicalPosition(new VisualPosition(newLineNumber, newColumnNumber));
      int offset = myEditor.logicalPositionToOffset(log);
      if (offset >= document.getTextLength()) {
        int lastOffsetColumn = myEditor.offsetToVisualPosition(document.getTextLength()).column;
        // We want to move caret to the last column if if it's located at the last line and 'Down'
        // is pressed.
        newColumnNumber = lastColumnNumber = Math.max(lastOffsetColumn, newColumnNumber);
        desiredX = -1;
      }
      CharSequence text = document.getCharsSequence();
      if (offset >= 0 && offset < document.getTextLength()) {
        if (text.charAt(offset) == '\t' && (columnShift <= 0 || offset == myOffset)) {
          if (columnShift <= 0) {
            newColumnNumber = myEditor.offsetToVisualPosition(offset).column;
          } else {
            SoftWrap softWrap = myEditor.getSoftWrapModel().getSoftWrap(offset + 1);
            // There is a possible case that tabulation symbol is the last document symbol
            // represented on a visual line before
            // soft wrap. We can't just use column from 'offset + 1' because it would point on a
            // next visual line.
            if (softWrap == null) {
              newColumnNumber = myEditor.offsetToVisualPosition(offset + 1).column;
            } else {
              newColumnNumber = EditorUtil.getLastVisualLineColumnNumber(myEditor, newLineNumber);
            }
          }
        }
      }
    }

    pos = new VisualPosition(newLineNumber, newColumnNumber);
    if (columnShift != 0 && lineShift == 0 && myEditor.getSoftWrapModel().isInsideSoftWrap(pos)) {
      LogicalPosition logical = myEditor.visualToLogicalPosition(pos);
      int softWrapOffset = myEditor.logicalPositionToOffset(logical);
      if (columnShift >= 0) {
        moveToOffset(softWrapOffset);
      } else {
        int line = myEditor.offsetToVisualLine(softWrapOffset - 1);
        moveToVisualPosition(
            new VisualPosition(line, EditorUtil.getLastVisualLineColumnNumber(myEditor, line)));
      }
    } else {
      moveToVisualPosition(pos);
      if (!editorSettings.isVirtualSpace() && columnShift == 0) {
        myEditor.setLastColumnNumber(lastColumnNumber);
      }
    }

    if (withSelection) {
      if (blockSelection) {
        selectionModel.setBlockSelection(blockSelectionStart, getLogicalPosition());
      } else {
        if (selectToDocumentStart) {
          selectionModel.setSelection(selectionStart, 0);
        } else if (pos.line >= myEditor.getVisibleLineCount()) {
          if (selectionStart < document.getTextLength()) {
            selectionModel.setSelection(selectionStart, document.getTextLength());
          }
        } else {
          selectionModel.setSelection(selectionStart, getVisualPosition(), getOffset());
        }
      }
    } else {
      selectionModel.removeSelection();
    }

    if (scrollToCaret) {
      myEditor.getScrollingModel().scrollToCaret(ScrollType.RELATIVE);
    }

    if (desiredX >= 0) {
      myDesiredX = desiredX;
    }

    EditorActionUtil.selectNonexpandableFold(myEditor);
  }
Example #7
0
    @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().trim().length()
                  : 1;
        }
      } catch (IncorrectOperationException e) {
        LOG.error(e);
      }

      myOffset = Math.min(myOffset, myDocument.getTextLength());
      caretModel.moveToOffset(myOffset);
      EditorModificationUtil.scrollToCaret(myEditor);
      myEditor.getSelectionModel().removeSelection();
      if (myCaretAdvance != 0) {
        LogicalPosition caretPosition = caretModel.getLogicalPosition();
        LogicalPosition pos =
            new LogicalPosition(caretPosition.line, caretPosition.column + myCaretAdvance);
        caretModel.moveToLogicalPosition(pos);
      }
    }