Search in sources :

Example 1 with WhiteSpaceFormattingStrategy

use of com.intellij.psi.formatter.WhiteSpaceFormattingStrategy in project intellij-community by JetBrains.

the class AutoHardWrapHandler method wrapLineIfNecessary.

/**
   * The user is allowed to configured IJ in a way that it automatically wraps line on right margin exceeding on typing
   * (check {@link EditorSettings#isWrapWhenTypingReachesRightMargin(Project)}).
   * <p/>
   * This method encapsulates that functionality, i.e. it performs the following logical actions:
   * <pre>
   * <ol>
   *   <li>Check if IJ is configured to perform automatic line wrapping on typing. Return in case of the negative answer;</li>
   *   <li>Check if right margin is exceeded. Return in case of the negative answer;</li>
   *   <li>Perform line wrapping;</li>
   * </ol>
   </pre>
   *
   * @param editor                          active editor
   * @param dataContext                     current data context
   * @param modificationStampBeforeTyping   document modification stamp before the current symbols typing
   */
public void wrapLineIfNecessary(@NotNull Editor editor, @NotNull DataContext dataContext, long modificationStampBeforeTyping) {
    Project project = editor.getProject();
    Document document = editor.getDocument();
    AutoWrapChange change = myAutoWrapChanges.get(document);
    if (change != null) {
        change.charTyped(editor, modificationStampBeforeTyping);
    }
    // Return eagerly if we don't need to auto-wrap line, e.g. because of right margin exceeding.
    if (/*editor.isOneLineMode()
        || */
    project == null || !editor.getSettings().isWrapWhenTypingReachesRightMargin(project) || (TemplateManager.getInstance(project) != null && TemplateManager.getInstance(project).getActiveTemplate(editor) != null)) {
        return;
    }
    CaretModel caretModel = editor.getCaretModel();
    int caretOffset = caretModel.getOffset();
    int line = document.getLineNumber(caretOffset);
    int startOffset = document.getLineStartOffset(line);
    int endOffset = document.getLineEndOffset(line);
    final CharSequence endOfString = document.getCharsSequence().subSequence(caretOffset, endOffset);
    final boolean endsWithSpaces = StringUtil.isEmptyOrSpaces(String.valueOf(endOfString));
    // Check if right margin is exceeded.
    int margin = editor.getSettings().getRightMargin(project);
    if (margin <= 0) {
        return;
    }
    VisualPosition visEndLinePosition = editor.offsetToVisualPosition(endOffset);
    if (margin >= visEndLinePosition.column) {
        if (change != null) {
            change.modificationStamp = document.getModificationStamp();
        }
        return;
    }
    // We assume that right margin is exceeded if control flow reaches this place. Hence, we define wrap position and perform
    // smart line break there.
    LineWrapPositionStrategy strategy = LanguageLineWrapPositionStrategy.INSTANCE.forEditor(editor);
    // We want to prevent such behavior, hence, we remove automatically generated wraps and wrap the line as a whole.
    if (change == null) {
        change = new AutoWrapChange();
        myAutoWrapChanges.put(document, change);
    } else {
        final int start = change.change.getStart();
        final int end = change.change.getEnd();
        if (!change.isEmpty() && start < end) {
            document.replaceString(start, end, change.change.getText());
        }
        change.reset();
    }
    change.update(editor);
    // Is assumed to be max possible number of characters inserted on the visual line with caret.
    int maxPreferredOffset = editor.logicalPositionToOffset(editor.visualToLogicalPosition(new VisualPosition(caretModel.getVisualPosition().line, margin - FormatConstants.RESERVED_LINE_WRAP_WIDTH_IN_COLUMNS)));
    int wrapOffset = strategy.calculateWrapPosition(document, project, startOffset, endOffset, maxPreferredOffset, true, false);
    if (wrapOffset < 0) {
        return;
    }
    WhiteSpaceFormattingStrategy formattingStrategy = WhiteSpaceFormattingStrategyFactory.getStrategy(editor);
    if (wrapOffset <= startOffset || wrapOffset > maxPreferredOffset || formattingStrategy.check(document.getCharsSequence(), startOffset, wrapOffset) >= wrapOffset) {
        // on first non-white space symbol because wrapped part will have the same indent value).
        return;
    }
    final int[] wrapIntroducedSymbolsNumber = new int[1];
    final int[] caretOffsetDiff = new int[1];
    final int baseCaretOffset = caretModel.getOffset();
    DocumentListener listener = new DocumentListener() {

        @Override
        public void beforeDocumentChange(DocumentEvent event) {
            if (event.getOffset() < baseCaretOffset + caretOffsetDiff[0]) {
                caretOffsetDiff[0] += event.getNewLength() - event.getOldLength();
            }
            if (autoFormatted(event)) {
                return;
            }
            wrapIntroducedSymbolsNumber[0] += event.getNewLength() - event.getOldLength();
        }

        private boolean autoFormatted(DocumentEvent event) {
            return event.getNewLength() <= event.getOldLength() && endsWithSpaces;
        }

        @Override
        public void documentChanged(DocumentEvent event) {
        }
    };
    caretModel.moveToOffset(wrapOffset);
    DataManager.getInstance().saveInDataContext(dataContext, AUTO_WRAP_LINE_IN_PROGRESS_KEY, true);
    document.addDocumentListener(listener);
    try {
        EditorActionManager.getInstance().getActionHandler(IdeActions.ACTION_EDITOR_ENTER).execute(editor, dataContext);
    } finally {
        DataManager.getInstance().saveInDataContext(dataContext, AUTO_WRAP_LINE_IN_PROGRESS_KEY, null);
        document.removeDocumentListener(listener);
    }
    change.modificationStamp = document.getModificationStamp();
    change.change.setStart(wrapOffset);
    change.change.setEnd(wrapOffset + wrapIntroducedSymbolsNumber[0]);
    caretModel.moveToOffset(baseCaretOffset + caretOffsetDiff[0]);
}
Also used : DocumentListener(com.intellij.openapi.editor.event.DocumentListener) WhiteSpaceFormattingStrategy(com.intellij.psi.formatter.WhiteSpaceFormattingStrategy) DocumentEvent(com.intellij.openapi.editor.event.DocumentEvent) Project(com.intellij.openapi.project.Project)

Example 2 with WhiteSpaceFormattingStrategy

use of com.intellij.psi.formatter.WhiteSpaceFormattingStrategy in project intellij-community by JetBrains.

the class AbstractXmlBlock method containsWhiteSpacesOnly.

public static boolean containsWhiteSpacesOnly(@NotNull ASTNode node) {
    PsiElement psiElement = node.getPsi();
    if (psiElement instanceof PsiWhiteSpace)
        return true;
    Language nodeLang = psiElement.getLanguage();
    if (!nodeLang.isKindOf(XMLLanguage.INSTANCE) || isTextOnlyNode(node) || node.getElementType() == XmlElementType.XML_PROLOG) {
        WhiteSpaceFormattingStrategy strategy = WhiteSpaceFormattingStrategyFactory.getStrategy(nodeLang);
        int length = node.getTextLength();
        return strategy.check(node.getChars(), 0, length) >= length;
    }
    return false;
}
Also used : WhiteSpaceFormattingStrategy(com.intellij.psi.formatter.WhiteSpaceFormattingStrategy) XMLLanguage(com.intellij.lang.xml.XMLLanguage)

Aggregations

WhiteSpaceFormattingStrategy (com.intellij.psi.formatter.WhiteSpaceFormattingStrategy)2 XMLLanguage (com.intellij.lang.xml.XMLLanguage)1 DocumentEvent (com.intellij.openapi.editor.event.DocumentEvent)1 DocumentListener (com.intellij.openapi.editor.event.DocumentListener)1 Project (com.intellij.openapi.project.Project)1