diff --git a/platform/platform-resources/src/idea/VcsActions.xml b/platform/platform-resources/src/idea/VcsActions.xml
index 9ca381f12921..738b0c6464b5 100644
--- a/platform/platform-resources/src/idea/VcsActions.xml
+++ b/platform/platform-resources/src/idea/VcsActions.xml
@@ -239,6 +239,7 @@
use-shortcut-of="Diff.ShowDiff" icon="AllIcons.Actions.Diff"/>
+
checkRightMargin(file, document, manager, isOnTheFly, line, RIGHT_MARGIN,
- format("Body lines should not exceed %d characters", RIGHT_MARGIN), new WrapLineQuickFix()))
+ format("Body lines should not exceed %d characters", RIGHT_MARGIN), new WrapLineQuickFix(),
+ new ReformatCommitMessageQuickFix()))
.filter(Objects::nonNull)
.toArray(ProblemDescriptor[]::new);
}
+ @Override
+ public boolean canReformat(@NotNull Project project, @NotNull Document document) {
+ return hasProblems(project, document);
+ }
+
+ @Override
+ public void reformat(@NotNull Project project, @NotNull Document document) {
+ new WrapLineQuickFix().doApplyFix(project, document, null);
+ }
+
protected class WrapLineQuickFix extends BaseCommitMessageQuickFix {
protected WrapLineQuickFix() {
super("Wrap line");
}
@Override
- public void doApplyFix(@NotNull Project project, @NotNull Document document, @NotNull ProblemDescriptor descriptor) {
+ public void doApplyFix(@NotNull Project project, @NotNull Document document, @Nullable ProblemDescriptor descriptor) {
Editor editor = CommitMessage.getEditor(document);
if (editor != null) {
- TextRange range = descriptor.getLineNumber() >= 0 ? getLineTextRange(document, descriptor.getLineNumber()) : EMPTY_RANGE;
+ TextRange range = descriptor != null && descriptor.getLineNumber() >= 0
+ ? getLineTextRange(document, descriptor.getLineNumber())
+ : getBodyRange(document);
if (!range.isEmpty()) {
wrapLines(project, editor, document, RIGHT_MARGIN, range);
@@ -88,6 +101,11 @@ public class BodyLimitInspection extends BaseCommitMessageInspection {
}
}
+ @NotNull
+ private TextRange getBodyRange(@NotNull Document document) {
+ return document.getLineCount() > 1 ? TextRange.create(document.getLineStartOffset(1), document.getTextLength()) : EMPTY_RANGE;
+ }
+
private void wrapLines(@NotNull Project project,
@NotNull Editor editor,
@NotNull Document document,
diff --git a/platform/vcs-impl/src/com/intellij/vcs/commit/ReformatCommitMessageAction.java b/platform/vcs-impl/src/com/intellij/vcs/commit/ReformatCommitMessageAction.java
new file mode 100644
index 000000000000..59dd15463666
--- /dev/null
+++ b/platform/vcs-impl/src/com/intellij/vcs/commit/ReformatCommitMessageAction.java
@@ -0,0 +1,90 @@
+/*
+ * Copyright 2000-2017 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.intellij.vcs.commit;
+
+import com.intellij.codeInspection.ex.InspectionToolWrapper;
+import com.intellij.codeInspection.ex.Tools;
+import com.intellij.openapi.actionSystem.AnActionEvent;
+import com.intellij.openapi.application.WriteAction;
+import com.intellij.openapi.command.CommandProcessor;
+import com.intellij.openapi.editor.Document;
+import com.intellij.openapi.editor.Editor;
+import com.intellij.openapi.project.DumbAwareAction;
+import com.intellij.openapi.project.Project;
+import com.intellij.openapi.vcs.VcsDataKeys;
+import com.intellij.openapi.vcs.ui.CommitMessage;
+import org.jetbrains.annotations.CalledWithWriteLock;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+import java.util.List;
+import java.util.stream.Stream;
+
+import static com.intellij.util.ObjectUtils.notNull;
+import static com.intellij.util.ObjectUtils.tryCast;
+import static java.util.stream.Collectors.toList;
+
+public class ReformatCommitMessageAction extends DumbAwareAction {
+
+ public static final String NAME = "Reformat commit message";
+
+ public ReformatCommitMessageAction() {
+ setEnabledInModalContext(true);
+ }
+
+ @Override
+ public void update(@NotNull AnActionEvent e) {
+ Project project = e.getProject();
+ Document document = getCommitMessage(e);
+
+ e.getPresentation().setEnabled(project != null &&
+ document != null &&
+ getEnabledInspections(project).anyMatch(inspection -> inspection.canReformat(project, document)));
+ }
+
+ @Override
+ public void actionPerformed(@NotNull AnActionEvent e) {
+ Project project = notNull(e.getProject());
+ Document document = notNull(getCommitMessage(e));
+
+ CommandProcessor.getInstance().executeCommand(project, () ->
+ WriteAction.run(() -> reformat(project, document)), NAME, null);
+ }
+
+ @CalledWithWriteLock
+ public static void reformat(@NotNull Project project, @NotNull Document document) {
+ List inspections = getEnabledInspections(project).collect(toList());
+
+ inspections.forEach(inspection -> inspection.reformat(project, document));
+ }
+
+ @Nullable
+ private static Document getCommitMessage(@NotNull AnActionEvent e) {
+ CommitMessage commitMessage = tryCast(e.getData(VcsDataKeys.COMMIT_MESSAGE_CONTROL), CommitMessage.class);
+ Editor editor = commitMessage != null ? commitMessage.getEditorField().getEditor() : null;
+
+ return editor != null ? editor.getDocument() : null;
+ }
+
+ @NotNull
+ private static Stream getEnabledInspections(@NotNull Project project) {
+ return CommitMessageInspectionProfile.getInstance(project).getAllEnabledInspectionTools(project).stream()
+ .map(Tools::getTool)
+ .map(InspectionToolWrapper::getTool)
+ .filter(BaseCommitMessageInspection.class::isInstance)
+ .map(BaseCommitMessageInspection.class::cast);
+ }
+}
diff --git a/platform/vcs-impl/src/com/intellij/vcs/commit/SubjectBodySeparationInspection.java b/platform/vcs-impl/src/com/intellij/vcs/commit/SubjectBodySeparationInspection.java
index e2ab65a10554..1890ceeb2e4a 100644
--- a/platform/vcs-impl/src/com/intellij/vcs/commit/SubjectBodySeparationInspection.java
+++ b/platform/vcs-impl/src/com/intellij/vcs/commit/SubjectBodySeparationInspection.java
@@ -44,26 +44,43 @@ public class SubjectBodySeparationInspection extends BaseCommitMessageInspection
boolean isOnTheFly) {
ProblemDescriptor descriptor = document.getLineCount() > 1
? checkRightMargin(file, document, manager, isOnTheFly, 1, 0,
- "Missing blank line between subject and body", new AddBlankLineQuickFix())
+ "Missing blank line between subject and body", new AddBlankLineQuickFix(),
+ new ReformatCommitMessageQuickFix())
: null;
return descriptor != null ? ar(descriptor) : null;
}
+ @Override
+ public boolean canReformat(@NotNull Project project, @NotNull Document document) {
+ return hasProblems(project, document);
+ }
+
+ @Override
+ public void reformat(@NotNull Project project, @NotNull Document document) {
+ new AddBlankLineQuickFix().doApplyFix(project, document, null);
+ }
+
protected static class AddBlankLineQuickFix extends BaseCommitMessageQuickFix {
protected AddBlankLineQuickFix() {
super("Add blank line");
}
@Override
- public void doApplyFix(@NotNull Project project, @NotNull Document document, @NotNull ProblemDescriptor descriptor) {
- if (descriptor.getLineNumber() >= 0) {
- TextRange lineRange = getLineTextRange(document, descriptor.getLineNumber());
+ public void doApplyFix(@NotNull Project project, @NotNull Document document, @Nullable ProblemDescriptor descriptor) {
+ int line = descriptor != null && descriptor.getLineNumber() >= 0 ? descriptor.getLineNumber() : getFirstLine(document);
+
+ if (line >= 0) {
+ TextRange lineRange = getLineTextRange(document, line);
if (!lineRange.isEmpty()) {
document.insertString(lineRange.getStartOffset(), "\n");
}
}
}
+
+ private static int getFirstLine(@NotNull Document document) {
+ return document.getLineCount() > 1 ? 1 : -1;
+ }
}
}