All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.jetbrains.python.formatter.PyWhiteSpaceFormattingStrategy Maven / Gradle / Ivy

Go to download

A packaging of the IntelliJ Community Edition python-community library. This is release number 1 of trunk branch 142.

The newest version!
/*
 * Copyright 2000-2014 JetBrains s.r.o.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.jetbrains.python.formatter;

import com.intellij.lang.ASTNode;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.psi.PsiElement;
import com.intellij.psi.codeStyle.CodeStyleSettings;
import com.intellij.psi.formatter.StaticSymbolWhiteSpaceDefinitionStrategy;
import com.jetbrains.python.editor.PythonEnterHandler;
import gnu.trove.TIntIntHashMap;
import gnu.trove.TIntProcedure;
import org.jetbrains.annotations.NotNull;

import java.util.concurrent.atomic.AtomicBoolean;

/**
 * @author yole
 */
public class PyWhiteSpaceFormattingStrategy extends StaticSymbolWhiteSpaceDefinitionStrategy {

  public PyWhiteSpaceFormattingStrategy() {
    super('\\');
  }

  @Override
  public CharSequence adjustWhiteSpaceIfNecessary(@NotNull CharSequence whiteSpaceText,
                                                  @NotNull PsiElement startElement,
                                                  int startOffset,
                                                  int endOffset,
                                                  CodeStyleSettings codeStyleSettings) {
    CharSequence whiteSpace =  super.adjustWhiteSpaceIfNecessary(whiteSpaceText, startElement, startOffset, endOffset, codeStyleSettings);
    if (whiteSpace.length() > 0 && whiteSpace.charAt(0) == '\n' && !StringUtil.contains(whiteSpace, 0, whiteSpace.length(), '\\') &&
        PythonEnterHandler.needInsertBackslash(startElement.getContainingFile(), startOffset, false)) {
      return addBackslashPrefix(whiteSpace, codeStyleSettings);
    }
    return whiteSpace;
  }

  private static String addBackslashPrefix(CharSequence whiteSpace, CodeStyleSettings settings) {
    PyCodeStyleSettings pySettings = settings.getCustomSettings(PyCodeStyleSettings.class);
    return (pySettings.SPACE_BEFORE_BACKSLASH ? " \\" : "\\") + whiteSpace.toString();
  }

  /**
   * Python uses backslashes at the end of the line as indication that next line is an extension of the current one.
   * 

* Hence, we need to preserve them during white space manipulation. * * * @param whiteSpaceText white space text to use by default for replacing sub-sequence of the given text * @param text target text which region is to be replaced by the given white space symbols * @param startOffset start offset to use with the given text (inclusive) * @param endOffset end offset to use with the given text (exclusive) * @param codeStyleSettings the code style settings * @param nodeAfter * @return symbols to use for replacing [startOffset; endOffset) sub-sequence of the given text */ @NotNull @Override public CharSequence adjustWhiteSpaceIfNecessary(@NotNull CharSequence whiteSpaceText, @NotNull CharSequence text, int startOffset, int endOffset, CodeStyleSettings codeStyleSettings, ASTNode nodeAfter) { // The general idea is that '\' symbol before line feed should be preserved. TIntIntHashMap initialBackSlashes = countBackSlashes(text, startOffset, endOffset); if (initialBackSlashes.isEmpty()) { if (nodeAfter != null && whiteSpaceText.length() > 0 && whiteSpaceText.charAt(0) == '\n' && PythonEnterHandler.needInsertBackslash(nodeAfter, false)) { return addBackslashPrefix(whiteSpaceText, codeStyleSettings); } return whiteSpaceText; } final TIntIntHashMap newBackSlashes = countBackSlashes(whiteSpaceText, 0, whiteSpaceText.length()); final AtomicBoolean continueProcessing = new AtomicBoolean(); initialBackSlashes.forEachKey(new TIntProcedure() { @Override public boolean execute(int key) { if (!newBackSlashes.containsKey(key)) { continueProcessing.set(true); return false; } return true; } }); if (!continueProcessing.get()) { return whiteSpaceText; } PyCodeStyleSettings settings = codeStyleSettings.getCustomSettings(PyCodeStyleSettings.class); StringBuilder result = new StringBuilder(); int line = 0; for (int i = 0; i < whiteSpaceText.length(); i++) { char c = whiteSpaceText.charAt(i); if (c != '\n') { result.append(c); continue; } if (!newBackSlashes.contains(line++)) { if ((i == 0 || (i > 0 && whiteSpaceText.charAt(i - 1) != ' ')) && settings.SPACE_BEFORE_BACKSLASH) { result.append(' '); } result.append('\\'); } result.append(c); } return result; } /** * Counts number of back slashes per-line. * * @param text target text * @param start start offset to use with the given text (inclusive) * @param end end offset to use with the given text (exclusive) * @return map that holds '{@code line number -> number of back slashes}' mapping for the target text */ static TIntIntHashMap countBackSlashes(CharSequence text, int start, int end) { TIntIntHashMap result = new TIntIntHashMap(); int line = 0; if (end > text.length()) { end = text.length(); } for (int i = start; i < end; i++) { char c = text.charAt(i); switch (c) { case '\n': line++; break; case '\\': result.put(line, 1); break; } } return result; } }





© 2015 - 2025 Weber Informatics LLC | Privacy Policy