예제 #1
0
파일: TabNanny.java 프로젝트: conbon/Pydev
  /**
   * Creates the errors that are related to a bad indentation (number of space chars is not ok).
   *
   * @param monitor
   */
  private static void createBadIndentForSpacesMessages(
      IDocument doc,
      IAnalysisPreferences analysisPrefs,
      IIndentPrefs indentPrefs,
      ArrayList<IMessage> ret,
      List<Tuple3<String, Integer, Boolean>> validsAre,
      IProgressMonitor monitor) {

    int tabWidth = indentPrefs.getTabWidth();
    // if we're analyzing the spaces, let's mark invalid indents (tabs are not searched for those
    // because
    // a tab always marks a full indent).

    FastStringBuffer buffer = new FastStringBuffer();
    for (Tuple3<String, Integer, Boolean> indentation : validsAre) {
      if (monitor.isCanceled()) {
        return;
      }

      if (!indentation
          .o3) { // if it does not have more contents (its only whitespaces), let's keep on going!
        continue;
      }
      String indentStr = indentation.o1;
      if (indentStr.indexOf("\t") != -1) {
        continue; // the ones that appear in tabs and spaces should not be analyzed here (they'll
        // have their own error messages).
      }

      int lenFound = indentStr.length();
      int extraChars = lenFound % tabWidth;
      if (extraChars != 0) {

        Integer offset = indentation.o2;
        int startLine = PySelection.getLineOfOffset(doc, offset) + 1;
        int startCol = 1;
        int endCol = startCol + lenFound;

        buffer.clear();
        ret.add(
            new Message(
                IAnalysisPreferences.TYPE_INDENTATION_PROBLEM,
                buffer.append("Bad Indentation (").append(lenFound).append(" spaces)").toString(),
                startLine,
                startLine,
                startCol,
                endCol,
                analysisPrefs));
      }
    }
  }
예제 #2
0
파일: TabNanny.java 프로젝트: conbon/Pydev
  /**
   * Analyze the doc for mixed tabs and indents with the wrong number of chars.
   *
   * @param monitor
   * @return a list with the error messages to be shown to the user.
   */
  public static List<IMessage> analyzeDoc(
      IDocument doc,
      IAnalysisPreferences analysisPrefs,
      String moduleName,
      IIndentPrefs indentPrefs,
      IProgressMonitor monitor) {
    ArrayList<IMessage> ret = new ArrayList<IMessage>();

    // don't even try to gather indentation errors if they should be ignored.
    if (analysisPrefs.getSeverityForType(IAnalysisPreferences.TYPE_INDENTATION_PROBLEM)
        == IMarker.SEVERITY_INFO) {
      return ret;
    }

    List<Tuple3<String, Integer, Boolean>> foundTabs =
        new ArrayList<Tuple3<String, Integer, Boolean>>();
    List<Tuple3<String, Integer, Boolean>> foundSpaces =
        new ArrayList<Tuple3<String, Integer, Boolean>>();

    TabNannyDocIterator it;
    try {
      it = new TabNannyDocIterator(doc);
    } catch (BadLocationException e) {
      return ret;
    }
    while (it.hasNext()) {
      Tuple3<String, Integer, Boolean> indentation;
      try {
        indentation = it.next();
      } catch (BadLocationException e) {
        return ret;
      }
      // it can actually be in both (if we have spaces and tabs in the same indent line).
      if (indentation.o1.indexOf('\t') != -1) {
        foundTabs.add(indentation);
      }
      if (indentation.o1.indexOf(' ') != -1) {
        foundSpaces.add(indentation);
      }
      if (monitor.isCanceled()) {
        return ret;
      }
    }

    int spacesFoundSize = foundSpaces.size();
    int tabsFoundSize = foundTabs.size();
    if (spacesFoundSize == 0 && tabsFoundSize == 0) {
      // nothing to do here... (no indents available)
      return ret;
    }

    // let's discover whether we should mark the tabs found as errors or the spaces found...
    boolean markTabsAsError;

    // if we found the same number of indents for tabs and spaces, let's use the user-prefs to
    // decide what to do
    if (spacesFoundSize == tabsFoundSize) {
      // ok, we have both, spaces and tabs... let's see what the user actually wants
      markTabsAsError = indentPrefs.getUseSpaces(false);

    } else if (tabsFoundSize > spacesFoundSize) {
      // let's see what appears more in the file (and mark the other as error).
      markTabsAsError = false;

    } else {
      markTabsAsError = true;
    }

    List<Tuple3<String, Integer, Boolean>> errorsAre;
    List<Tuple3<String, Integer, Boolean>> validsAre;
    String errorMsg;
    char errorChar;

    if (markTabsAsError) {
      validsAre = foundSpaces;
      errorsAre = foundTabs;
      errorMsg = "Mixed Indentation: Tab found";
      errorChar = '\t';

      createBadIndentForSpacesMessages(doc, analysisPrefs, indentPrefs, ret, validsAre, monitor);

    } else {
      validsAre = foundTabs;
      errorsAre = foundSpaces;
      errorMsg = "Mixed Indentation: Spaces found";
      errorChar = ' ';
    }

    createMixedErrorMessages(doc, analysisPrefs, ret, errorsAre, errorMsg, errorChar, monitor);
    return ret;
  }
  /**
   * Performs the action with a given PySelection
   *
   * @param ps Given PySelection
   * @return boolean The success or failure of the action
   */
  public int perform(PySelection ps) {
    // What we'll be replacing the selected text with
    FastStringBuffer strbuf = new FastStringBuffer();

    try {
      // discover 1st line that starts the block comment
      int i;
      int startLineIndex = getStartIndex(ps);
      int endLineIndex = getEndIndex(ps);
      if (startLineIndex == -1 || endLineIndex == -1) {
        if (startLineIndex == -1 && endLineIndex == -1) {
          return -1;
        } else if (startLineIndex == -1) {
          startLineIndex = endLineIndex;
        } else {
          endLineIndex = startLineIndex;
        }
      }

      // For each line, uncomment it
      for (i = startLineIndex; i <= endLineIndex; i++) {
        boolean addDelim = true;
        String spacesBefore = "";
        String line = ps.getLine(i);
        int lineLen = line.length();
        for (int j = 0; j < lineLen; j++) {
          char c = line.charAt(j);
          if (c == '#') {
            // ok, it starts with # (so, remove the whitespaces before it)
            if (j > 0) {
              spacesBefore = line.substring(0, j);
            }
            line = line.substring(j);
            break;
          } else {
            if (!Character.isWhitespace(c)) {
              break;
            }
          }
        }
        if (line.startsWith("#")) {
          line = line.substring(1);
        }

        // get the chars used in block-comments
        AbstractBlockCommentAction[] acts =
            new AbstractBlockCommentAction[] {
              new PyAddSingleBlockComment(), new PyAddBlockComment()
            };
        HashSet<Character> chars = new HashSet<Character>();
        for (int j = 0; j < acts.length; j++) {
          AbstractBlockCommentAction action = acts[j];
          chars.add(action.getColsAndChar().o2);
        }

        if (line.length() > 0) {
          boolean removedChar = false;
          char lastChar = '\0';
          for (int j = 0; j < line.length(); j++) {
            lastChar = line.charAt(j);
            if (!chars.contains(lastChar)) {
              break;
            } else {
              removedChar = true;
              line = line.substring(1);
              j--;
            }
          }
          if (line.length() == 0 && removedChar) {
            addDelim = false;
          }
          if (removedChar && lastChar == ' ') {
            line = line.substring(1);
          }
        }

        if (addDelim) {
          strbuf.append(spacesBefore);
          strbuf.append(line);
          String lineDelimiter = ps.getDoc().getLineDelimiter(i);
          if (lineDelimiter != null) {
            strbuf.append(lineDelimiter);
          }
        }
      }

      // Ok, at this point things should be correct, but make sure than on uncomment,
      // the code goes to a proper indent position (remove spaces we may have added when creating a
      // block).
      String string = strbuf.toString();
      List<String> lines = StringUtils.splitInLines(string);
      Tuple<Integer, String> posAndLine = new Tuple<Integer, String>(-1, "");
      for (String line : lines) {
        int firstCharPosition = PySelection.getFirstCharPosition(line);
        if (firstCharPosition < posAndLine.o1 || posAndLine.o1 < 0) {
          posAndLine.o1 = firstCharPosition;
          posAndLine.o2 = line;
        }
      }
      if (posAndLine.o1 > 0) {
        final String sub = posAndLine.o2.substring(0, posAndLine.o1);
        if (sub.endsWith(
            " ")) { // If it ends with a tab, we won't change anything (only spaces are removed --
                    // which we may have introduced)
          boolean allEqual = true;
          for (String line : lines) {
            if (!line.startsWith(sub)) {
              allEqual = false;
              break;
            }
          }
          if (allEqual) {
            if (sub.startsWith("\t")) {
              // Tabs based indent: remove any ending spaces (and at this point we know a string
              // ends with a space)
              int j;
              for (j = sub.length() - 1; j >= 0; j--) {
                char c = sub.charAt(j);
                if (c != ' ') {
                  j++;
                  break;
                }
              }
              String newSub = sub.substring(0, j);
              strbuf.clear();
              for (String line : lines) {
                strbuf.append(newSub);
                strbuf.append(line.substring(sub.length()));
              }

            } else {
              IIndentPrefs indentPrefs;
              if (targetEditor instanceof PyEdit) {
                PyEdit pyEdit = (PyEdit) targetEditor;
                indentPrefs = pyEdit.getIndentPrefs();
              } else {
                indentPrefs = DefaultIndentPrefs.get();
              }

              String indentationString = indentPrefs.getIndentationString();

              int subLen = sub.length();
              int indentLen = indentationString.length();
              int mod = subLen % indentLen;
              if (mod != 0) {
                String substring = sub.substring(subLen - mod, subLen);
                boolean onlyWhitespaces = true;
                for (int k = 0; k < substring.length(); k++) {
                  if (substring.charAt(k) != ' ') {
                    onlyWhitespaces = false;
                    break;
                  }
                }
                if (onlyWhitespaces) {
                  String newSub = sub.substring(0, subLen - mod);
                  strbuf.clear();
                  for (String line : lines) {
                    strbuf.append(newSub);
                    strbuf.append(line.substring(sub.length()));
                  }
                }
              }
            }
          }
        }
      }

      // Replace the text with the modified information
      int startLineOffset = ps.getLineOffset(startLineIndex);
      int endLineOffset = ps.getEndLineOffset(endLineIndex);
      String endLineDelimiter = ps.getDoc().getLineDelimiter(endLineIndex);
      if (endLineDelimiter != null) {
        endLineOffset += endLineDelimiter.length();
      }
      String str = strbuf.toString();
      ps.getDoc().replace(startLineOffset, endLineOffset - startLineOffset, str);
      return startLineOffset + str.length();
    } catch (Exception e) {
      beep(e);
    }

    // In event of problems, return false
    return -1;
  }