예제 #1
0
  @SuppressWarnings("unchecked")
  private static <E extends ArrangementEntry> void doArrange(
      @NotNull List<ArrangementEntryWrapper<E>> wrappers, @NotNull Context<E> context) {
    if (wrappers.isEmpty()) {
      return;
    }

    Map<E, ArrangementEntryWrapper<E>> map = ContainerUtilRt.newHashMap();
    List<E> arranged = ContainerUtilRt.newArrayList();
    List<E> toArrange = ContainerUtilRt.newArrayList();
    for (ArrangementEntryWrapper<E> wrapper : wrappers) {
      E entry = wrapper.getEntry();
      map.put(wrapper.getEntry(), wrapper);
      if (!entry.canBeMatched()) {
        // Split entries to arrange by 'can not be matched' rules.
        // See IDEA-104046 for a problem use-case example.
        if (toArrange.isEmpty()) {
          arranged.addAll(arrange(toArrange, context.rules, context.rulesByPriority));
        }
        arranged.add(entry);
        toArrange.clear();
      } else {
        toArrange.add(entry);
      }
    }
    if (!toArrange.isEmpty()) {
      arranged.addAll(arrange(toArrange, context.rules, context.rulesByPriority));
    }

    context.changer.prepare(wrappers, context);
    // We apply changes from the last position to the first position in order not to bother with
    // offsets shifts.
    for (int i = arranged.size() - 1; i >= 0; i--) {
      ArrangementEntryWrapper<E> arrangedWrapper = map.get(arranged.get(i));
      ArrangementEntryWrapper<E> initialWrapper = wrappers.get(i);
      context.changer.replace(
          arrangedWrapper, initialWrapper, i > 0 ? map.get(arranged.get(i - 1)) : null, context);
    }
  }
예제 #2
0
    @SuppressWarnings("AssignmentToForLoopParameter")
    @Override
    public void replace(
        @NotNull ArrangementEntryWrapper<E> newWrapper,
        @NotNull ArrangementEntryWrapper<E> oldWrapper,
        @Nullable ArrangementEntryWrapper<E> previous,
        @NotNull Context<E> context) {
      // Calculate blank lines before the arrangement.
      int blankLinesBefore = oldWrapper.getBlankLinesBefore();

      ArrangementEntryWrapper<E> parentWrapper = oldWrapper.getParent();
      int desiredBlankLinesNumber =
          context.rearranger.getBlankLines(
              context.settings,
              parentWrapper == null ? null : parentWrapper.getEntry(),
              previous == null ? null : previous.getEntry(),
              newWrapper.getEntry());
      if ((desiredBlankLinesNumber < 0 || desiredBlankLinesNumber == blankLinesBefore)
          && newWrapper.equals(oldWrapper)) {
        return;
      }

      int lineFeedsDiff = desiredBlankLinesNumber - blankLinesBefore;
      int insertionOffset = oldWrapper.getStartOffset();
      if (oldWrapper.getStartOffset() > newWrapper.getStartOffset()) {
        insertionOffset -= newWrapper.getEndOffset() - newWrapper.getStartOffset();
      }
      if (newWrapper.getStartOffset() != oldWrapper.getStartOffset()
          || !newWrapper.equals(oldWrapper)) {
        context.addMoveInfo(
            newWrapper.getStartOffset(), newWrapper.getEndOffset(), oldWrapper.getStartOffset());
        myDocument.moveText(
            newWrapper.getStartOffset(), newWrapper.getEndOffset(), oldWrapper.getStartOffset());
        for (int i = myWrappers.size() - 1; i >= 0; i--) {
          ArrangementEntryWrapper<E> w = myWrappers.get(i);
          if (w == newWrapper) {
            continue;
          }
          if (w.getStartOffset() >= oldWrapper.getStartOffset()
              && w.getStartOffset() < newWrapper.getStartOffset()) {
            w.applyShift(newWrapper.getEndOffset() - newWrapper.getStartOffset());
          } else if (w.getStartOffset() < oldWrapper.getStartOffset()
              && w.getStartOffset() > newWrapper.getStartOffset()) {
            w.applyShift(newWrapper.getStartOffset() - newWrapper.getEndOffset());
          }
        }
      }

      if (desiredBlankLinesNumber >= 0 && lineFeedsDiff > 0) {
        myDocument.insertString(insertionOffset, StringUtil.repeat("\n", lineFeedsDiff));
        shiftOffsets(lineFeedsDiff, insertionOffset);
      }

      if (desiredBlankLinesNumber >= 0 && lineFeedsDiff < 0) {
        // Cut exceeding blank lines.
        int replacementStartOffset = getBlankLineOffset(-lineFeedsDiff, insertionOffset);
        myDocument.deleteString(replacementStartOffset, insertionOffset);
        shiftOffsets(replacementStartOffset - insertionOffset, insertionOffset);
      }

      // Update wrapper ranges.
      if (desiredBlankLinesNumber < 0 || lineFeedsDiff == 0 || parentWrapper == null) {
        return;
      }

      Deque<ArrangementEntryWrapper<E>> parents = new ArrayDeque<ArrangementEntryWrapper<E>>();
      do {
        parents.add(parentWrapper);
        parentWrapper.setEndOffset(parentWrapper.getEndOffset() + lineFeedsDiff);
        parentWrapper = parentWrapper.getParent();
      } while (parentWrapper != null);

      while (!parents.isEmpty()) {
        for (ArrangementEntryWrapper<E> wrapper = parents.removeLast().getNext();
            wrapper != null;
            wrapper = wrapper.getNext()) {
          wrapper.applyShift(lineFeedsDiff);
        }
      }
    }
예제 #3
0
    @SuppressWarnings("AssignmentToForLoopParameter")
    @Override
    public void replace(
        @NotNull ArrangementEntryWrapper<E> newWrapper,
        @NotNull ArrangementEntryWrapper<E> oldWrapper,
        @Nullable ArrangementEntryWrapper<E> previous,
        @NotNull Context<E> context) {
      // Calculate blank lines before the arrangement.
      int blankLinesBefore = 0;
      TIntArrayList lineFeedOffsets = new TIntArrayList();
      int oldStartLine = context.document.getLineNumber(oldWrapper.getStartOffset());
      if (oldStartLine > 0) {
        int lastLineFeed = context.document.getLineStartOffset(oldStartLine) - 1;
        lineFeedOffsets.add(lastLineFeed);
        for (int i = lastLineFeed - 1 - myParentShift; i >= 0; i--) {
          i = CharArrayUtil.shiftBackward(myParentText, i, " \t");
          if (myParentText.charAt(i) == '\n') {
            blankLinesBefore++;
            lineFeedOffsets.add(i + myParentShift);
          } else {
            break;
          }
        }
      }

      ArrangementEntryWrapper<E> parentWrapper = oldWrapper.getParent();
      int desiredBlankLinesNumber =
          context.rearranger.getBlankLines(
              context.settings,
              parentWrapper == null ? null : parentWrapper.getEntry(),
              previous == null ? null : previous.getEntry(),
              newWrapper.getEntry());
      if (desiredBlankLinesNumber == blankLinesBefore && newWrapper.equals(oldWrapper)) {
        return;
      }

      String newEntryText =
          myParentText.substring(
              newWrapper.getStartOffset() - myParentShift,
              newWrapper.getEndOffset() - myParentShift);
      int lineFeedsDiff = desiredBlankLinesNumber - blankLinesBefore;
      if (lineFeedsDiff == 0 || desiredBlankLinesNumber < 0) {
        context.addMoveInfo(
            newWrapper.getStartOffset() - myParentShift,
            newWrapper.getEndOffset() - myParentShift,
            oldWrapper.getStartOffset());
        context.document.replaceString(
            oldWrapper.getStartOffset(), oldWrapper.getEndOffset(), newEntryText);
        return;
      }

      if (lineFeedsDiff > 0) {
        // Insert necessary number of blank lines.
        StringBuilder buffer = new StringBuilder(StringUtil.repeat("\n", lineFeedsDiff));
        buffer.append(newEntryText);
        context.document.replaceString(
            oldWrapper.getStartOffset(), oldWrapper.getEndOffset(), buffer);
      } else {
        // Cut exceeding blank lines.
        int replacementStartOffset = lineFeedOffsets.get(-lineFeedsDiff) + 1;
        context.document.replaceString(
            replacementStartOffset, oldWrapper.getEndOffset(), newEntryText);
      }

      // Update wrapper ranges.
      ArrangementEntryWrapper<E> parent = oldWrapper.getParent();
      if (parent == null) {
        return;
      }

      Deque<ArrangementEntryWrapper<E>> parents = new ArrayDeque<ArrangementEntryWrapper<E>>();
      do {
        parents.add(parent);
        parent.setEndOffset(parent.getEndOffset() + lineFeedsDiff);
        parent = parent.getParent();
      } while (parent != null);

      while (!parents.isEmpty()) {

        for (ArrangementEntryWrapper<E> wrapper = parents.removeLast().getNext();
            wrapper != null;
            wrapper = wrapper.getNext()) {
          wrapper.applyShift(lineFeedsDiff);
        }
      }
    }