private static int getLeftMostLine(IDocument document, ILineRange lines, int tabSize)
     throws BadLocationException {
   int numberOfLines = lines.getNumberOfLines();
   int first = lines.getStartLine();
   int minLine = -1;
   int minIndent = Integer.MAX_VALUE;
   for (int line = 0; line < numberOfLines; line++) {
     int length = computeVisualLength(getCurrentIndent(document, line + first), tabSize);
     if (length < minIndent) {
       minIndent = length;
       minLine = line;
     }
   }
   return minLine;
 }
  /**
   * Shifts the line range specified by <code>lines</code> in <code>document</code>. The amount that
   * the lines get shifted are determined by the first line in the range, all subsequent lines are
   * adjusted accordingly. The passed Java project may be <code>null</code>, it is used solely to
   * obtain formatter preferences.
   *
   * @param document the document to be changed
   * @param lines the line range to be shifted
   * @param project the Java project to get the formatter preferences from, or <code>null</code> if
   *     global preferences should be used
   * @param result the result from a previous call to <code>shiftLines</code>, in order to maintain
   *     comment line properties, or <code>null</code>. Note that the passed result may be changed
   *     by the call.
   * @return an indent result that may be queried for changes and can be reused in subsequent
   *     indentation operations
   * @throws BadLocationException if <code>lines</code> is not a valid line range on <code>document
   *     </code>
   */
  public static IndentResult shiftLines(
      IDocument document, ILineRange lines, IJavaProject project, IndentResult result)
      throws BadLocationException {
    int numberOfLines = lines.getNumberOfLines();

    if (numberOfLines < 1) return new IndentResult(null);

    result = reuseOrCreateToken(result, numberOfLines);
    result.hasChanged = false;

    JavaHeuristicScanner scanner = new JavaHeuristicScanner(document);
    JavaIndenter indenter = new JavaIndenter(document, scanner, project);

    String current = getCurrentIndent(document, lines.getStartLine());
    StringBuffer correct =
        indenter.computeIndentation(document.getLineOffset(lines.getStartLine()));
    if (correct == null) return result; // bail out

    int tabSize = CodeFormatterUtil.getTabWidth(project);
    StringBuffer addition = new StringBuffer();
    int difference = subtractIndent(correct, current, addition, tabSize);

    if (difference == 0) return result;

    if (result.leftmostLine == -1) result.leftmostLine = getLeftMostLine(document, lines, tabSize);

    int maxReduction =
        computeVisualLength(
            getCurrentIndent(document, result.leftmostLine + lines.getStartLine()), tabSize);

    if (difference > 0) {
      for (int line = lines.getStartLine(), last = line + numberOfLines, i = 0; line < last; line++)
        addIndent(document, line, addition, result.commentLinesAtColumnZero, i++);
    } else {
      int reduction = Math.min(-difference, maxReduction);
      for (int line = lines.getStartLine(), last = line + numberOfLines, i = 0; line < last; line++)
        cutIndent(document, line, reduction, tabSize, result.commentLinesAtColumnZero, i++);
    }

    result.hasChanged = true;

    return result;
  }
  /**
   * Indents the line range specified by <code>lines</code> in <code>document</code>. The passed
   * Java project may be <code>null</code>, it is used solely to obtain formatter preferences.
   *
   * @param document the document to be changed
   * @param lines the line range to be indented
   * @param project the Java project to get the formatter preferences from, or <code>null</code> if
   *     global preferences should be used
   * @param result the result from a previous call to <code>indentLines</code>, in order to maintain
   *     comment line properties, or <code>null</code>. Note that the passed result may be changed
   *     by the call.
   * @return an indent result that may be queried for changes and can be reused in subsequent
   *     indentation operations
   * @throws BadLocationException if <code>lines</code> is not a valid line range on <code>document
   *     </code>
   */
  public static IndentResult indentLines(
      IDocument document, ILineRange lines, IJavaProject project, IndentResult result)
      throws BadLocationException {
    int numberOfLines = lines.getNumberOfLines();

    if (numberOfLines < 1) return new IndentResult(null);

    result = reuseOrCreateToken(result, numberOfLines);

    JavaHeuristicScanner scanner = new JavaHeuristicScanner(document);
    JavaIndenter indenter = new JavaIndenter(document, scanner, project);
    boolean changed = false;
    int tabSize = CodeFormatterUtil.getTabWidth(project);
    for (int line = lines.getStartLine(), last = line + numberOfLines, i = 0; line < last; line++) {
      changed |=
          indentLine(
              document, line, indenter, scanner, result.commentLinesAtColumnZero, i++, tabSize);
    }
    result.hasChanged = changed;

    return result;
  }