예제 #1
0
  /**
   * Returns the indentation of the line <code>line</code> in <code>document</code>. The returned
   * string may contain pairs of leading slashes that are considered part of the indentation. The
   * space before the asterisk in a javadoc-like comment is not considered part of the indentation.
   *
   * @param document the document
   * @param line the line
   * @return the indentation of <code>line</code> in <code>document</code>
   * @throws BadLocationException if the document is changed concurrently
   */
  private static String getCurrentIndent(Document document, int line) throws BadLocationException {
    IRegion region = document.getLineInformation(line);
    int from = region.getOffset();
    int endOffset = region.getOffset() + region.getLength();

    // go behind line comments
    int to = from;
    while (to < endOffset - 2 && document.get(to, 2).equals(LINE_COMMENT)) to += 2;

    while (to < endOffset) {
      char ch = document.getChar(to);
      if (!Character.isWhitespace(ch)) break;
      to++;
    }

    // don't count the space before javadoc like, asterisk-style comment lines
    if (to > from && to < endOffset - 1 && document.get(to - 1, 2).equals(" *")) { // $NON-NLS-1$
      String type =
          TextUtilities.getContentType(document, IJavaPartitions.JAVA_PARTITIONING, to, true);
      if (type.equals(IJavaPartitions.JAVA_DOC)
          || type.equals(IJavaPartitions.JAVA_MULTI_LINE_COMMENT)) to--;
    }

    return document.get(from, to - from);
  }
예제 #2
0
  /**
   * Indents line <code>line</code> in <code>document</code> with <code>indent</code>. Leaves
   * leading comment signs alone.
   *
   * @param document the document
   * @param line the line
   * @param indent the indentation to insert
   * @param tabLength the length of a tab
   * @throws BadLocationException on concurrent document modification
   */
  private void addIndent(Document document, int line, CharSequence indent, int tabLength)
      throws BadLocationException {
    IRegion region = document.getLineInformation(line);
    int insert = region.getOffset();
    int endOffset = region.getOffset() + region.getLength();

    // Compute insert after all leading line comment markers
    int newInsert = insert;
    while (newInsert < endOffset - 2 && document.get(newInsert, 2).equals(LINE_COMMENT))
      newInsert += 2;

    // Heuristic to check whether it is commented code or just a comment
    if (newInsert > insert) {
      int whitespaceCount = 0;
      int i = newInsert;
      while (i < endOffset - 1) {
        char ch = document.get(i, 1).charAt(0);
        if (!Character.isWhitespace(ch)) break;
        whitespaceCount = whitespaceCount + computeVisualLength(ch, tabLength);
        i++;
      }

      if (whitespaceCount != 0 && whitespaceCount >= CodeFormatterUtil.getIndentWidth(fProject))
        insert = newInsert;
    }

    // Insert indent
    document.replace(insert, 0, indent.toString());
  }
예제 #3
0
  /**
   * Cuts the visual equivalent of <code>toDelete</code> characters out of the indentation of line
   * <code>line</code> in <code>document</code>. Leaves leading comment signs alone.
   *
   * @param document the document
   * @param line the line
   * @param toDelete the number of space equivalents to delete
   * @param tabLength the length of a tab
   * @throws BadLocationException on concurrent document modification
   */
  private void cutIndent(Document document, int line, int toDelete, int tabLength)
      throws BadLocationException {
    IRegion region = document.getLineInformation(line);
    int from = region.getOffset();
    int endOffset = region.getOffset() + region.getLength();

    // go behind line comments
    while (from < endOffset - 2 && document.get(from, 2).equals(LINE_COMMENT)) from += 2;

    int to = from;
    while (toDelete > 0 && to < endOffset) {
      char ch = document.getChar(to);
      if (!Character.isWhitespace(ch)) break;
      toDelete -= computeVisualLength(ch, tabLength);
      if (toDelete >= 0) to++;
      else break;
    }

    document.replace(from, to - from, ""); // $NON-NLS-1$
  }
예제 #4
0
  private void smartPaste(IDocument document, DocumentCommand command) {
    int newOffset = command.offset;
    int newLength = command.length;
    String newText = command.text;

    try {
      JavaHeuristicScanner scanner = new JavaHeuristicScanner(document);
      JavaIndenter indenter = new JavaIndenter(document, scanner, fProject);
      int offset = newOffset;

      // reference position to get the indent from
      int refOffset = indenter.findReferencePosition(offset);
      if (refOffset == JavaHeuristicScanner.NOT_FOUND) return;
      int peerOffset = getPeerPosition(document, command);
      peerOffset = indenter.findReferencePosition(peerOffset);
      if (peerOffset != JavaHeuristicScanner.NOT_FOUND) refOffset = Math.min(refOffset, peerOffset);

      // eat any WS before the insertion to the beginning of the line
      int firstLine =
          1; // don't format the first line per default, as it has other content before it
      IRegion line = document.getLineInformationOfOffset(offset);
      String notSelected = document.get(line.getOffset(), offset - line.getOffset());
      if (notSelected.trim().length() == 0) {
        newLength += notSelected.length();
        newOffset = line.getOffset();
        firstLine = 0;
      }

      // prefix: the part we need for formatting but won't paste
      IRegion refLine = document.getLineInformationOfOffset(refOffset);
      String prefix = document.get(refLine.getOffset(), newOffset - refLine.getOffset());

      // handle the indentation computation inside a temporary document
      Document temp = new Document(prefix + newText);
      DocumentRewriteSession session =
          temp.startRewriteSession(DocumentRewriteSessionType.STRICTLY_SEQUENTIAL);
      scanner = new JavaHeuristicScanner(temp);
      indenter = new JavaIndenter(temp, scanner, fProject);
      installJavaStuff(temp);

      // indent the first and second line
      // compute the relative indentation difference from the second line
      // (as the first might be partially selected) and use the value to
      // indent all other lines.
      boolean isIndentDetected = false;
      StringBuffer addition = new StringBuffer();
      int insertLength = 0;
      int firstLineInsertLength = 0;
      int firstLineIndent = 0;
      int first = document.computeNumberOfLines(prefix) + firstLine; // don't format first line
      int lines = temp.getNumberOfLines();
      int tabLength = getVisualTabLengthPreference();
      boolean changed = false;
      for (int l = first;
          l < lines;
          l++) { // we don't change the number of lines while adding indents

        IRegion r = temp.getLineInformation(l);
        int lineOffset = r.getOffset();
        int lineLength = r.getLength();

        if (lineLength == 0) // don't modify empty lines
        continue;

        if (!isIndentDetected) {

          // indent the first pasted line
          String current = getCurrentIndent(temp, l);
          StringBuffer correct = indenter.computeIndentation(lineOffset);
          if (correct == null) return; // bail out

          insertLength = subtractIndent(correct, current, addition, tabLength);
          if (l == first) {
            firstLineInsertLength = insertLength;
            firstLineIndent = current.length();
          }
          if (l != first && temp.get(lineOffset, lineLength).trim().length() != 0) {
            isIndentDetected = true;
            if (firstLineIndent >= current.length()) insertLength = firstLineInsertLength;
            if (insertLength == 0) {
              // no adjustment needed, bail out
              if (firstLine == 0) {
                // but we still need to adjust the first line
                command.offset = newOffset;
                command.length = newLength;
                if (changed) break; // still need to get the leading indent of the first line
              }
              return;
            }
          } else {
            changed = insertLength != 0;
          }
        }

        // relatively indent all pasted lines
        if (insertLength > 0) addIndent(temp, l, addition, tabLength);
        else if (insertLength < 0) cutIndent(temp, l, -insertLength, tabLength);
      }

      removeJavaStuff(temp);
      temp.stopRewriteSession(session);
      newText = temp.get(prefix.length(), temp.getLength() - prefix.length());

      command.offset = newOffset;
      command.length = newLength;
      command.text = newText;

    } catch (BadLocationException e) {
      JavaPlugin.log(e);
    }
  }