mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
Merge branch 'no-reformat-dialog-on-reformat-code-action'
This commit is contained in:
@@ -28,6 +28,7 @@ import com.intellij.psi.PsiJavaFile;
|
||||
import com.intellij.psi.codeStyle.JavaCodeStyleManager;
|
||||
import com.intellij.util.IncorrectOperationException;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
/**
|
||||
* @author max
|
||||
@@ -44,7 +45,10 @@ public class JavaImportOptimizer implements ImportOptimizer {
|
||||
Project project = file.getProject();
|
||||
final PsiImportList newImportList = JavaCodeStyleManager.getInstance(project).prepareOptimizeImportsResult((PsiJavaFile)file);
|
||||
if (newImportList == null) return EmptyRunnable.getInstance();
|
||||
return new Runnable() {
|
||||
|
||||
return new CollectingInfoRunnable() {
|
||||
private int myImportListLengthDiff = 0;
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
try {
|
||||
@@ -55,12 +59,23 @@ public class JavaImportOptimizer implements ImportOptimizer {
|
||||
}
|
||||
final PsiImportList oldImportList = ((PsiJavaFile)file).getImportList();
|
||||
assert oldImportList != null;
|
||||
int importsBefore = oldImportList.getAllImportStatements().length;
|
||||
oldImportList.replace(newImportList);
|
||||
myImportListLengthDiff = importsBefore - newImportList.getAllImportStatements().length;
|
||||
}
|
||||
catch (IncorrectOperationException e) {
|
||||
LOG.error(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public String getUserNotificationInfo() {
|
||||
if (myImportListLengthDiff > 0) {
|
||||
return "removed " + myImportListLengthDiff + " import" + (myImportListLengthDiff > 1 ? "s" : "");
|
||||
}
|
||||
return null;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
+14
@@ -0,0 +1,14 @@
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
|
||||
public class Test {
|
||||
|
||||
public static void main(String[] args) {
|
||||
List<String> list = new ArrayList<String>();
|
||||
int a = 3;
|
||||
|
||||
int b = 3;
|
||||
}
|
||||
|
||||
}
|
||||
+17
@@ -0,0 +1,17 @@
|
||||
import java.lang.String;
|
||||
import java.util.List;
|
||||
import java.util.HashMap;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashSet;
|
||||
|
||||
|
||||
public class Test {
|
||||
|
||||
public static void main(String[] args) {
|
||||
<selection>List<String> list = new ArrayList<String>();
|
||||
int a = 3;</selection>
|
||||
|
||||
int b = 3;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
public class Test {
|
||||
|
||||
int a = 2;
|
||||
int b = 3;
|
||||
|
||||
|
||||
public void run() {
|
||||
int myFirst = 12;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
public class Test {
|
||||
|
||||
<selection>int a = 2;
|
||||
int b = 3;</selection>
|
||||
|
||||
|
||||
public void run() {
|
||||
int myFirst = 12;
|
||||
}
|
||||
|
||||
}
|
||||
+11
@@ -0,0 +1,11 @@
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
|
||||
public class Test {
|
||||
|
||||
public static void main(String[] args) {
|
||||
List<String> list = new ArrayList<String>();
|
||||
}
|
||||
|
||||
}
|
||||
+14
@@ -0,0 +1,14 @@
|
||||
import java.lang.String;
|
||||
import java.util.List;
|
||||
import java.util.HashMap;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashSet;
|
||||
|
||||
|
||||
public class Test {
|
||||
|
||||
public static void main(String[] args) {
|
||||
List<String> list = new ArrayList<String>();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
public class Test {
|
||||
|
||||
public int a = 3;
|
||||
|
||||
|
||||
public void test() {
|
||||
int c = 3;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
public class Test {
|
||||
|
||||
public int a = 3;
|
||||
|
||||
|
||||
public void test() {
|
||||
int c = 3;
|
||||
}
|
||||
|
||||
}
|
||||
+6
-48
@@ -316,14 +316,9 @@ class AdditionalEventInfo {
|
||||
}
|
||||
}
|
||||
|
||||
class MockReformatFileSettings implements LayoutCodeOptions {
|
||||
private boolean myProcessWholeFile;
|
||||
private boolean myProcessDirectories;
|
||||
private boolean myRearrange;
|
||||
private boolean myIncludeSubdirs;
|
||||
class MockReformatFileSettings implements ReformatFilesOptions {
|
||||
private boolean myOptimizeImports;
|
||||
private boolean myProcessOnlyChangedText;
|
||||
private boolean myIsOK = true;
|
||||
private boolean myIncludeSubdirs;
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
@@ -338,33 +333,13 @@ class MockReformatFileSettings implements LayoutCodeOptions {
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isProcessWholeFile() {
|
||||
return myProcessWholeFile;
|
||||
}
|
||||
|
||||
MockReformatFileSettings setProcessWholeFile(boolean processWholeFile) {
|
||||
myProcessWholeFile = processWholeFile;
|
||||
return this;
|
||||
public TextRangeType getTextRangeType() {
|
||||
return TextRangeType.WHOLE_FILE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isProcessDirectory() {
|
||||
return myProcessDirectories;
|
||||
}
|
||||
|
||||
MockReformatFileSettings setProcessDirectory(boolean processDirectories) {
|
||||
myProcessDirectories = processDirectories;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isRearrangeEntries() {
|
||||
return myRearrange;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isIncludeSubdirectories() {
|
||||
return myIncludeSubdirs;
|
||||
public boolean isRearrangeCode() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -378,23 +353,6 @@ class MockReformatFileSettings implements LayoutCodeOptions {
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isProcessOnlyChangedText() {
|
||||
return myProcessOnlyChangedText;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
MockReformatFileSettings setProcessOnlyChangedText(boolean processOnlyChangedText) {
|
||||
myProcessOnlyChangedText = processOnlyChangedText;
|
||||
return this;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
MockReformatFileSettings setRearrange(boolean rearrange) {
|
||||
myRearrange = rearrange;
|
||||
return this;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
MockReformatFileSettings setIncludeSubdirs(boolean includeSubdirs) {
|
||||
myIncludeSubdirs = includeSubdirs;
|
||||
|
||||
+44
-60
@@ -16,106 +16,90 @@
|
||||
package com.intellij.codeInsight.actions;
|
||||
|
||||
import com.intellij.JavaTestUtil;
|
||||
import com.intellij.openapi.actionSystem.*;
|
||||
import com.intellij.openapi.editor.Document;
|
||||
import com.intellij.openapi.editor.Editor;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.vcs.FilePath;
|
||||
import com.intellij.openapi.vcs.VcsException;
|
||||
import com.intellij.openapi.vcs.changes.Change;
|
||||
import com.intellij.openapi.vcs.changes.ContentRevision;
|
||||
import com.intellij.openapi.vcs.history.VcsRevisionNumber;
|
||||
import com.intellij.psi.PsiFile;
|
||||
import com.intellij.testFramework.fixtures.LightCodeInsightFixtureTestCase;
|
||||
import org.jetbrains.annotations.NonNls;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import com.intellij.testFramework.fixtures.LightPlatformCodeInsightFixtureTestCase;
|
||||
|
||||
public class ReformatCodeActionInEditorTest extends LightCodeInsightFixtureTestCase {
|
||||
import static com.intellij.codeInsight.actions.TextRangeType.*;
|
||||
|
||||
public class ReformatCodeActionInEditorTest extends LightPlatformCodeInsightFixtureTestCase {
|
||||
|
||||
@Override
|
||||
protected String getTestDataPath() {
|
||||
return JavaTestUtil.getJavaTestDataPath() + "/actions/reformatFileInEditor/";
|
||||
}
|
||||
|
||||
public void doTest(@NotNull ReformatFilesOptions options) {
|
||||
setOptions(options);
|
||||
|
||||
String before = null;
|
||||
if (options.isProcessOnlyChangedText()) {
|
||||
myFixture.configureByFile(getTestName(true) + "_revision.java");
|
||||
PsiFile file = myFixture.getFile();
|
||||
Document document = myFixture.getDocument(file);
|
||||
before = document.getText();
|
||||
}
|
||||
|
||||
myFixture.configureByFile(getTestName(true) + "_before.java");
|
||||
|
||||
if (before != null) {
|
||||
myFixture.getFile().putUserData(FormatChangedTextUtil.TEST_REVISION_CONTENT, before);
|
||||
}
|
||||
|
||||
final String actionId = IdeActions.ACTION_EDITOR_REFORMAT;
|
||||
AnAction action = ActionManager.getInstance().getAction(actionId);
|
||||
|
||||
AnActionEvent event = createEventFor(action, getProject(), myFixture.getEditor());
|
||||
|
||||
action.actionPerformed(event);
|
||||
myFixture.checkResultByFile(getTestName(true) + "_after.java");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void tearDown() throws Exception {
|
||||
myFixture.getFile().putUserData(FormatChangedTextUtil.TEST_REVISION_CONTENT, null);
|
||||
super.tearDown();
|
||||
}
|
||||
|
||||
protected AnActionEvent createEventFor(@NotNull AnAction action, @NotNull final Project project, @NotNull final Editor editor) {
|
||||
return new AnActionEvent(null, new DataContext() {
|
||||
@Nullable
|
||||
@Override
|
||||
public Object getData(@NonNls String dataId) {
|
||||
if (CommonDataKeys.PROJECT.is(dataId)) return project;
|
||||
if (CommonDataKeys.EDITOR.is(dataId)) return editor;
|
||||
return null;
|
||||
}
|
||||
}, "", action.getTemplatePresentation(), ActionManager.getInstance(), 0);
|
||||
public void doTest(LayoutCodeOptions options) {
|
||||
CharSequence revisionContent = null;
|
||||
if (options.getTextRangeType() == VCS_CHANGED_TEXT) {
|
||||
myFixture.configureByFile(getTestName(true) + "_revision.java");
|
||||
PsiFile file = myFixture.getFile();
|
||||
Document document = myFixture.getDocument(file);
|
||||
revisionContent = document.getCharsSequence();
|
||||
}
|
||||
|
||||
myFixture.configureByFile(getTestName(true) + "_before.java");
|
||||
if (revisionContent != null) {
|
||||
myFixture.getFile().putUserData(FormatChangedTextUtil.TEST_REVISION_CONTENT, revisionContent);
|
||||
}
|
||||
|
||||
FileInEditorProcessor processor = new FileInEditorProcessor(myFixture.getFile(), myFixture.getEditor(), options);
|
||||
|
||||
processor.processCode();
|
||||
myFixture.checkResultByFile(getTestName(true) + "_after.java");
|
||||
}
|
||||
|
||||
protected void setOptions(ReformatFilesOptions options) {
|
||||
ReformatCodeAction.setTestOptions(options);
|
||||
public void testSelectionReformat() {
|
||||
doTest(new ReformatCodeRunOptions(SELECTED_TEXT));
|
||||
}
|
||||
|
||||
public void testWholeFileReformat() {
|
||||
doTest(new ReformatCodeRunOptions(WHOLE_FILE));
|
||||
}
|
||||
|
||||
public void testWholeFileReformatAndOptimize() {
|
||||
doTest(new ReformatCodeRunOptions(WHOLE_FILE).setOptimizeImports(true));
|
||||
}
|
||||
|
||||
public void testSelectedTextAndOptimizeImports() {
|
||||
doTest(new ReformatCodeRunOptions(SELECTED_TEXT).setOptimizeImports(true));
|
||||
}
|
||||
|
||||
public void testFormatWholeFile() {
|
||||
doTest(new MockReformatFileSettings().setProcessWholeFile(true));
|
||||
doTest(new ReformatCodeRunOptions(WHOLE_FILE));
|
||||
}
|
||||
|
||||
public void testFormatOptimizeWholeFile() {
|
||||
doTest(new MockReformatFileSettings().setProcessWholeFile(true).setOptimizeImports(true));
|
||||
doTest(new ReformatCodeRunOptions(WHOLE_FILE).setOptimizeImports(true));
|
||||
}
|
||||
|
||||
public void testFormatOptimizeRearrangeWholeFile() {
|
||||
doTest(new MockReformatFileSettings().setProcessWholeFile(true).setOptimizeImports(true).setRearrange(true));
|
||||
doTest(new ReformatCodeRunOptions(WHOLE_FILE).setOptimizeImports(true).setRearrangeCode(true));
|
||||
}
|
||||
|
||||
public void testFormatSelection() {
|
||||
doTest(new MockReformatFileSettings().setProcessWholeFile(false));
|
||||
doTest(new ReformatCodeRunOptions(SELECTED_TEXT));
|
||||
}
|
||||
|
||||
public void testFormatRearrangeSelection() {
|
||||
doTest(new MockReformatFileSettings().setProcessWholeFile(false).setRearrange(true));
|
||||
doTest(new ReformatCodeRunOptions(SELECTED_TEXT).setRearrangeCode(true));
|
||||
}
|
||||
|
||||
public void testFormatVcsChanges() {
|
||||
doTest(new MockReformatFileSettings().setProcessOnlyChangedText(true));
|
||||
doTest(new ReformatCodeRunOptions(VCS_CHANGED_TEXT));
|
||||
}
|
||||
|
||||
public void testFormatOptimizeVcsChanges() {
|
||||
doTest(new MockReformatFileSettings().setProcessOnlyChangedText(true).setOptimizeImports(true));
|
||||
doTest(new ReformatCodeRunOptions(VCS_CHANGED_TEXT).setOptimizeImports(true));
|
||||
}
|
||||
|
||||
public void testFormatOptimizeRearrangeVcsChanges() {
|
||||
doTest(new MockReformatFileSettings().setProcessOnlyChangedText(true).setOptimizeImports(true).setRearrange(true));
|
||||
doTest(new ReformatCodeRunOptions(VCS_CHANGED_TEXT).setOptimizeImports(true).setRearrangeCode(true));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -35,35 +35,10 @@ public class ReformatCodeActionTest extends AbstractLayoutCodeProcessorTest {
|
||||
public void testReformatAndOptimizeMultipleFiles() throws IOException {
|
||||
List<PsiFile> files = createTestFiles(getTempRootDirectory(), classNames);
|
||||
injectMockDialogFlags(new MockReformatFileSettings().setOptimizeImports(true));
|
||||
|
||||
performReformatActionOnSelectedFiles(files);
|
||||
checkFormationAndImportsOptimizationFor(files);
|
||||
}
|
||||
|
||||
public void testReformatSingleSelectedFile() throws IOException {
|
||||
List<PsiFile> files = createTestFiles(getTempRootDirectory(), classNames);
|
||||
PsiFile fileToReformat = files.get(0);
|
||||
List<PsiFile> shouldNotBeFormatted = files.subList(1, files.size());
|
||||
injectMockDialogFlags(new MockReformatFileSettings().setOptimizeImports(true));
|
||||
|
||||
performReformatActionOnSelectedFile(fileToReformat);
|
||||
|
||||
checkFormationAndImportsOptimizationFor(Arrays.asList(fileToReformat));
|
||||
checkNoProcessingWasPerformedOn(shouldNotBeFormatted);
|
||||
}
|
||||
|
||||
public void testReformatAndOptimizeFileFromEditor() throws IOException {
|
||||
List<PsiFile> files = createTestFiles(getTempRootDirectory(), classNames);
|
||||
injectMockDialogFlags(new MockReformatFileSettings().setOptimizeImports(true));
|
||||
|
||||
PsiFile fileToFormat = files.get(0);
|
||||
List<PsiFile> shouldNotBeFormatted = files.subList(1, files.size());
|
||||
|
||||
performReformatActionOnFileInEditor(fileToFormat);
|
||||
checkFormationAndImportsOptimizationFor(Arrays.asList(fileToFormat));
|
||||
checkNoProcessingWasPerformedOn(shouldNotBeFormatted);
|
||||
}
|
||||
|
||||
public void testOptimizeAndReformatOnlySelectedFiles() throws IOException {
|
||||
List<PsiFile> files = createTestFiles(getTempRootDirectory(), classNames);
|
||||
List<PsiFile> forProcessing = ContainerUtil.newArrayList(files.get(0), files.get(1));
|
||||
@@ -77,28 +52,6 @@ public class ReformatCodeActionTest extends AbstractLayoutCodeProcessorTest {
|
||||
checkNoProcessingWasPerformedOn(noProcessing);
|
||||
}
|
||||
|
||||
public void testOptimizeAndReformatAllFilesInDirectoryIncludeSubdirs() throws IOException {
|
||||
TestFileStructure fileStructure = getThreeLevelDirectoryStructure();
|
||||
injectMockDialogFlags(new MockReformatFileSettings().setOptimizeImports(true).setProcessDirectory(true).setIncludeSubdirs(true));
|
||||
PsiFile fileInEditor = fileStructure.getFilesAtLevel(2).get(0);
|
||||
List<PsiFile> shouldNotBeFormatted = fileStructure.getFilesAtLevel(1);
|
||||
|
||||
performReformatActionOnFileInEditor(fileInEditor);
|
||||
|
||||
checkFormationAndImportsOptimizationFor(fileStructure.getFilesAtLevel(2), fileStructure.getFilesAtLevel(3));
|
||||
checkNoProcessingWasPerformedOn(shouldNotBeFormatted);
|
||||
}
|
||||
|
||||
public void testOptimizeAndReformatAllFilesInDirectoryExcludeSubdirs() throws IOException {
|
||||
TestFileStructure fileStructure = getThreeLevelDirectoryStructure();
|
||||
injectMockDialogFlags(new MockReformatFileSettings().setOptimizeImports(true).setIncludeSubdirs(false));
|
||||
|
||||
performReformatActionOnSelectedFiles(fileStructure.getFilesAtLevel(2));
|
||||
|
||||
checkFormationAndImportsOptimizationFor(fileStructure.getFilesAtLevel(2));
|
||||
checkNoProcessingWasPerformedOn(fileStructure.getFilesAtLevel(1), fileStructure.getFilesAtLevel(3));
|
||||
}
|
||||
|
||||
public void testOptimizeAndReformatInModule() throws IOException {
|
||||
Module module = createModuleWithSourceRoot("newModule");
|
||||
VirtualFile srcDir = ModuleRootManager.getInstance(module).getSourceRoots()[0];
|
||||
@@ -109,26 +62,4 @@ public class ReformatCodeActionTest extends AbstractLayoutCodeProcessorTest {
|
||||
|
||||
checkFormationAndImportsOptimizationFor(files);
|
||||
}
|
||||
|
||||
private TestFileStructure getThreeLevelDirectoryStructure() throws IOException {
|
||||
TestFileStructure fileStructure = new TestFileStructure(getModule(), getTempRootDirectory());
|
||||
|
||||
fileStructure.createDirectoryAndMakeItCurrent("dir");
|
||||
addFilesToCurrentDirectory(fileStructure);
|
||||
|
||||
fileStructure.createDirectoryAndMakeItCurrent("innerDir");
|
||||
addFilesToCurrentDirectory(fileStructure);
|
||||
|
||||
fileStructure.createDirectoryAndMakeItCurrent("innerInnerDir");
|
||||
addFilesToCurrentDirectory(fileStructure);
|
||||
|
||||
return fileStructure;
|
||||
}
|
||||
|
||||
private void addFilesToCurrentDirectory(TestFileStructure fileStructure) throws IOException {
|
||||
for (int i = 0; i < 5; i++) {
|
||||
String className = "Test" + i;
|
||||
fileStructure.addTestFile("Test" + i + ".java", getUntouchedJavaSourceForTotalProcessing(className));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,6 +18,7 @@ package com.intellij.lang;
|
||||
|
||||
import com.intellij.psi.PsiFile;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
/**
|
||||
* Implementers of the interface encapsulate optimize imports process for the language.
|
||||
@@ -50,4 +51,11 @@ public interface ImportOptimizer {
|
||||
@NotNull
|
||||
Runnable processFile(PsiFile file);
|
||||
|
||||
/**
|
||||
* In order to customize notification popup after reformat code action just return it from {@link #processFile} with proper information,
|
||||
* by default "imports optimized" is shown.
|
||||
*/
|
||||
interface CollectingInfoRunnable extends Runnable {
|
||||
@Nullable String getUserNotificationInfo();
|
||||
}
|
||||
}
|
||||
|
||||
+9
-1
@@ -21,6 +21,7 @@ import com.intellij.openapi.actionSystem.AnActionEvent;
|
||||
import com.intellij.openapi.actionSystem.CommonDataKeys;
|
||||
import com.intellij.openapi.editor.Document;
|
||||
import com.intellij.openapi.editor.Editor;
|
||||
import com.intellij.openapi.editor.SelectionModel;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.psi.PsiDocumentManager;
|
||||
import com.intellij.psi.PsiFile;
|
||||
@@ -61,6 +62,13 @@ public class RearrangeCodeAction extends AnAction {
|
||||
if (file == null) {
|
||||
return;
|
||||
}
|
||||
new RearrangeCodeProcessor(project, file, editor.getSelectionModel()).run();
|
||||
|
||||
SelectionModel model = editor.getSelectionModel();
|
||||
if (model.hasSelection()) {
|
||||
new RearrangeCodeProcessor(file, model).run();
|
||||
}
|
||||
else {
|
||||
new RearrangeCodeProcessor(file).run();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+58
-1
@@ -18,12 +18,16 @@ package com.intellij.codeInsight.actions;
|
||||
|
||||
import com.intellij.codeInsight.CodeInsightBundle;
|
||||
import com.intellij.lang.LanguageFormatting;
|
||||
import com.intellij.notification.Notification;
|
||||
import com.intellij.notification.NotificationType;
|
||||
import com.intellij.openapi.application.ApplicationBundle;
|
||||
import com.intellij.openapi.application.ApplicationBundle;
|
||||
import com.intellij.openapi.application.ApplicationManager;
|
||||
import com.intellij.openapi.application.ModalityState;
|
||||
import com.intellij.openapi.command.CommandProcessor;
|
||||
import com.intellij.openapi.diagnostic.Logger;
|
||||
import com.intellij.openapi.editor.Document;
|
||||
import com.intellij.openapi.editor.SelectionModel;
|
||||
import com.intellij.openapi.fileEditor.FileDocumentManager;
|
||||
import com.intellij.openapi.module.Module;
|
||||
import com.intellij.openapi.progress.ProcessCanceledException;
|
||||
@@ -37,6 +41,7 @@ import com.intellij.openapi.project.ProjectUtil;
|
||||
import com.intellij.openapi.roots.GeneratedSourcesFilter;
|
||||
import com.intellij.openapi.ui.Messages;
|
||||
import com.intellij.openapi.ui.ex.MessagesEx;
|
||||
import com.intellij.openapi.util.TextRange;
|
||||
import com.intellij.openapi.vfs.VirtualFile;
|
||||
import com.intellij.psi.PsiBundle;
|
||||
import com.intellij.psi.PsiDirectory;
|
||||
@@ -45,7 +50,9 @@ import com.intellij.psi.PsiFile;
|
||||
import com.intellij.util.IncorrectOperationException;
|
||||
import com.intellij.util.SequentialModalProgressTask;
|
||||
import com.intellij.util.SequentialTask;
|
||||
import com.intellij.util.SmartList;
|
||||
import com.intellij.util.containers.ContainerUtil;
|
||||
import com.intellij.util.diff.FilesTooBigForDiffException;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
@@ -69,12 +76,14 @@ public abstract class AbstractLayoutCodeProcessor {
|
||||
|
||||
private final String myProgressText;
|
||||
private final String myCommandName;
|
||||
private final Runnable myPostRunnable;
|
||||
private Runnable myPostRunnable;
|
||||
private boolean myProcessChangedTextOnly;
|
||||
|
||||
protected AbstractLayoutCodeProcessor myPreviousCodeProcessor;
|
||||
private List<FileFilter> myFilters = ContainerUtil.newArrayList();
|
||||
|
||||
private LayoutCodeInfoCollector myInfoCollector;
|
||||
|
||||
protected AbstractLayoutCodeProcessor(Project project, String commandName, String progressText, boolean processChangedTextOnly) {
|
||||
this(project, (Module)null, commandName, progressText, processChangedTextOnly);
|
||||
}
|
||||
@@ -96,6 +105,7 @@ public abstract class AbstractLayoutCodeProcessor {
|
||||
myCommandName = commandName;
|
||||
myPreviousCodeProcessor = previous;
|
||||
myFilters = previous.myFilters;
|
||||
myInfoCollector = previous.myInfoCollector;
|
||||
}
|
||||
|
||||
protected AbstractLayoutCodeProcessor(Project project,
|
||||
@@ -171,12 +181,26 @@ public abstract class AbstractLayoutCodeProcessor {
|
||||
return list;
|
||||
}
|
||||
|
||||
public void setPostRunnable(Runnable postRunnable) {
|
||||
myPostRunnable = postRunnable;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private FutureTask<Boolean> getPreviousProcessorTask(@NotNull PsiFile file, boolean processChangedTextOnly) {
|
||||
return myPreviousCodeProcessor != null ? myPreviousCodeProcessor.preprocessFile(file, processChangedTextOnly)
|
||||
: null;
|
||||
}
|
||||
|
||||
public void setCollectInfo(boolean isCollectInfo) {
|
||||
myInfoCollector = isCollectInfo ? new LayoutCodeInfoCollector() : null;
|
||||
|
||||
AbstractLayoutCodeProcessor current = this;
|
||||
while (current.myPreviousCodeProcessor != null) {
|
||||
current = current.myPreviousCodeProcessor;
|
||||
current.myInfoCollector = myInfoCollector;
|
||||
}
|
||||
}
|
||||
|
||||
public void addFileFilter(@NotNull FileFilter filter) {
|
||||
myFilters.add(filter);
|
||||
}
|
||||
@@ -584,4 +608,37 @@ public abstract class AbstractLayoutCodeProcessor {
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
protected static List<TextRange> getSelectedRanges(@NotNull SelectionModel selectionModel) {
|
||||
final List<TextRange> ranges = new SmartList<TextRange>();
|
||||
if (selectionModel.hasSelection()) {
|
||||
TextRange range = TextRange.create(selectionModel.getSelectionStart(), selectionModel.getSelectionEnd());
|
||||
ranges.add(range);
|
||||
}
|
||||
else if (selectionModel.hasBlockSelection()) {
|
||||
int[] starts = selectionModel.getBlockSelectionStarts();
|
||||
int[] ends = selectionModel.getBlockSelectionEnds();
|
||||
for (int i = 0; i < starts.length; i++) {
|
||||
ranges.add(TextRange.create(starts[i], ends[i]));
|
||||
}
|
||||
}
|
||||
|
||||
return ranges;
|
||||
}
|
||||
|
||||
protected void handleFileTooBigException(Logger logger, FilesTooBigForDiffException e, @NotNull PsiFile file) {
|
||||
logger.info("Error while calculating changed ranges for: " + file.getVirtualFile(), e);
|
||||
if (!ApplicationManager.getApplication().isUnitTestMode()) {
|
||||
Notification notification = new Notification(ApplicationBundle.message("reformat.changed.text.file.too.big.notification.groupId"),
|
||||
ApplicationBundle.message("reformat.changed.text.file.too.big.notification.title"),
|
||||
ApplicationBundle.message("reformat.changed.text.file.too.big.notification.text", file.getName()),
|
||||
NotificationType.INFORMATION);
|
||||
notification.notify(file.getProject());
|
||||
}
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public LayoutCodeInfoCollector getInfoCollector() {
|
||||
return myInfoCollector;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,206 @@
|
||||
/*
|
||||
* Copyright 2000-2014 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.codeInsight.actions;
|
||||
|
||||
import com.intellij.codeInsight.hint.HintManager;
|
||||
import com.intellij.codeInsight.hint.HintManagerImpl;
|
||||
import com.intellij.codeInsight.hint.HintUtil;
|
||||
import com.intellij.openapi.actionSystem.ActionManager;
|
||||
import com.intellij.openapi.application.Application;
|
||||
import com.intellij.openapi.application.ApplicationManager;
|
||||
import com.intellij.openapi.diagnostic.Logger;
|
||||
import com.intellij.openapi.editor.Editor;
|
||||
import com.intellij.openapi.keymap.KeymapUtil;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.util.text.StringUtil;
|
||||
import com.intellij.psi.PsiFile;
|
||||
import com.intellij.ui.ColorUtil;
|
||||
import com.intellij.ui.JBColor;
|
||||
import com.intellij.ui.LightweightHint;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import javax.swing.*;
|
||||
|
||||
import static com.intellij.codeInsight.actions.TextRangeType.*;
|
||||
|
||||
class FileInEditorProcessor {
|
||||
private static final Logger LOG = Logger.getInstance(FileInEditorProcessor.class);
|
||||
|
||||
private final Editor myEditor;
|
||||
|
||||
private boolean myNoChangesDetected = false;
|
||||
private final boolean myProcessChangesTextOnly;
|
||||
|
||||
private final boolean myShouldOptimizeImports;
|
||||
private final boolean myShouldRearrangeCode;
|
||||
private final boolean myProcessSelectedText;
|
||||
|
||||
private final Project myProject;
|
||||
|
||||
private final PsiFile myFile;
|
||||
private AbstractLayoutCodeProcessor myProcessor;
|
||||
|
||||
public FileInEditorProcessor(PsiFile file,
|
||||
Editor editor,
|
||||
LayoutCodeOptions runOptions)
|
||||
{
|
||||
myFile = file;
|
||||
myProject = file.getProject();
|
||||
myEditor = editor;
|
||||
|
||||
myShouldOptimizeImports = runOptions.isOptimizeImports();
|
||||
myShouldRearrangeCode = runOptions.isRearrangeCode();
|
||||
myProcessSelectedText = myEditor != null && runOptions.getTextRangeType() == SELECTED_TEXT;
|
||||
myProcessChangesTextOnly = runOptions.getTextRangeType() == VCS_CHANGED_TEXT;
|
||||
}
|
||||
|
||||
public void processCode() {
|
||||
if (myShouldOptimizeImports) {
|
||||
myProcessor = new OptimizeImportsProcessor(myProject, myFile);
|
||||
}
|
||||
|
||||
if (myProcessChangesTextOnly && !FormatChangedTextUtil.hasChanges(myFile)) {
|
||||
myNoChangesDetected = true;
|
||||
}
|
||||
|
||||
myProcessor = mixWithReformatProcessor(myProcessor);
|
||||
if (myShouldRearrangeCode) {
|
||||
myProcessor = mixWithRearrangeProcessor(myProcessor);
|
||||
}
|
||||
|
||||
if (shouldNotify()) {
|
||||
myProcessor.setCollectInfo(true);
|
||||
myProcessor.setPostRunnable(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
String message = prepareMessage();
|
||||
if (!myEditor.isDisposed() && myEditor.getComponent().isShowing()) {
|
||||
showHint(myEditor, message);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
myProcessor.run();
|
||||
}
|
||||
|
||||
private AbstractLayoutCodeProcessor mixWithRearrangeProcessor(@NotNull AbstractLayoutCodeProcessor processor) {
|
||||
if (myProcessSelectedText) {
|
||||
processor = new RearrangeCodeProcessor(processor, myEditor.getSelectionModel());
|
||||
}
|
||||
else {
|
||||
processor = new RearrangeCodeProcessor(processor);
|
||||
}
|
||||
return processor;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private AbstractLayoutCodeProcessor mixWithReformatProcessor(@Nullable AbstractLayoutCodeProcessor processor) {
|
||||
if (processor != null) {
|
||||
if (myProcessSelectedText) {
|
||||
processor = new ReformatCodeProcessor(processor, myEditor.getSelectionModel());
|
||||
}
|
||||
else {
|
||||
processor = new ReformatCodeProcessor(processor, myProcessChangesTextOnly);
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (myProcessSelectedText) {
|
||||
processor = new ReformatCodeProcessor(myFile, myEditor.getSelectionModel());
|
||||
}
|
||||
else {
|
||||
processor = new ReformatCodeProcessor(myFile, myProcessChangesTextOnly);
|
||||
}
|
||||
}
|
||||
return processor;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private String prepareMessage() {
|
||||
StringBuilder builder = new StringBuilder("<html>");
|
||||
LayoutCodeInfoCollector notifications = myProcessor.getInfoCollector();
|
||||
LOG.assertTrue(notifications != null);
|
||||
|
||||
if (notifications.isEmpty() && !myNoChangesDetected) {
|
||||
if (myProcessChangesTextOnly) {
|
||||
builder.append("No lines changed: changes since last revision are already properly formatted").append("<br>");
|
||||
}
|
||||
else {
|
||||
builder.append("No lines changed: code is already properly formatted").append("<br>");
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (notifications.hasReformatOrRearrangeNotification()) {
|
||||
String reformatInfo = notifications.getReformatCodeNotification();
|
||||
String rearrangeInfo = notifications.getRearrangeCodeNotification();
|
||||
|
||||
builder.append(joinWithCommaAndCapitalize(reformatInfo, rearrangeInfo));
|
||||
|
||||
if (myProcessChangesTextOnly) {
|
||||
builder.append(" in changes since last revision");
|
||||
}
|
||||
|
||||
builder.append("<br>");
|
||||
}
|
||||
else if (myNoChangesDetected) {
|
||||
builder.append("No lines changed: no changes since last revision").append("<br>");
|
||||
}
|
||||
|
||||
String optimizeImportsNotification = notifications.getOptimizeImportsNotification();
|
||||
if (optimizeImportsNotification != null) {
|
||||
builder.append(StringUtil.capitalize(optimizeImportsNotification)).append("<br>");
|
||||
}
|
||||
}
|
||||
|
||||
String shortcutText = KeymapUtil.getFirstKeyboardShortcutText(ActionManager.getInstance().getAction("ShowReformatFileDialog"));
|
||||
String color = ColorUtil.toHex(JBColor.gray);
|
||||
|
||||
builder.append("<span style='color:#").append(color).append("'>")
|
||||
.append("Show reformat dialog: ").append(shortcutText).append("</span>")
|
||||
.append("</html>");
|
||||
|
||||
return builder.toString();
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private String joinWithCommaAndCapitalize(String reformatNotification, String rearrangeNotification) {
|
||||
String firstNotificationLine = reformatNotification != null ? reformatNotification : rearrangeNotification;
|
||||
if (reformatNotification != null && rearrangeNotification != null) {
|
||||
firstNotificationLine += ", " + rearrangeNotification;
|
||||
}
|
||||
firstNotificationLine = StringUtil.capitalize(firstNotificationLine);
|
||||
return firstNotificationLine;
|
||||
}
|
||||
|
||||
private static void showHint(@NotNull Editor editor, @NotNull String info) {
|
||||
JComponent component = HintUtil.createInformationLabel(info);
|
||||
LightweightHint hint = new LightweightHint(component);
|
||||
HintManagerImpl.getInstanceImpl().showEditorHint(hint, editor, HintManager.UNDER,
|
||||
HintManager.HIDE_BY_ANY_KEY |
|
||||
HintManager.HIDE_BY_TEXT_CHANGE |
|
||||
HintManager.HIDE_BY_SCROLLING,
|
||||
0, false);
|
||||
}
|
||||
|
||||
private boolean shouldNotify() {
|
||||
Application application = ApplicationManager.getApplication();
|
||||
if (application.isUnitTestMode() || application.isHeadlessEnvironment()) {
|
||||
return false;
|
||||
}
|
||||
return myEditor != null && !myProcessSelectedText;
|
||||
}
|
||||
}
|
||||
+50
-38
@@ -54,9 +54,10 @@ import org.jetbrains.annotations.Nullable;
|
||||
import java.util.*;
|
||||
|
||||
public class FormatChangedTextUtil {
|
||||
public static final Key<String> TEST_REVISION_CONTENT = Key.create("test.revision.content");
|
||||
public static final Key<CharSequence> TEST_REVISION_CONTENT = Key.create("test.revision.content");
|
||||
private static final Logger LOG = Logger.getInstance("#com.intellij.codeInsight.actions.FormatChangedTextUtil");
|
||||
|
||||
|
||||
private FormatChangedTextUtil() {
|
||||
}
|
||||
|
||||
@@ -71,26 +72,9 @@ public class FormatChangedTextUtil {
|
||||
final VirtualFile virtualFile = file.getVirtualFile();
|
||||
if (virtualFile != null) {
|
||||
final Change change = ChangeListManager.getInstance(project).getChange(virtualFile);
|
||||
if (change != null && change.getType() == Change.Type.NEW) {
|
||||
return true;
|
||||
}
|
||||
return change != null;
|
||||
}
|
||||
|
||||
final LineStatusTrackerManagerI manager = LineStatusTrackerManager.getInstance(project);
|
||||
if (manager == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
final Document document = PsiDocumentManager.getInstance(project).getDocument(file);
|
||||
if (document == null) {
|
||||
return false;
|
||||
}
|
||||
final LineStatusTracker lineStatusTracker = manager.getLineStatusTracker(document);
|
||||
if (lineStatusTracker == null) {
|
||||
return false;
|
||||
}
|
||||
final List<Range> ranges = lineStatusTracker.getRanges();
|
||||
return !ranges.isEmpty();
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -249,15 +233,18 @@ public class FormatChangedTextUtil {
|
||||
|
||||
@NotNull
|
||||
public static List<TextRange> getChangedTextRanges(@NotNull Project project, @NotNull PsiFile file) throws FilesTooBigForDiffException {
|
||||
List<TextRange> cachedChangedLines = getCachedChangedLines(project, file);
|
||||
Document document = PsiDocumentManager.getInstance(project).getDocument(file);
|
||||
if (document == null) return ContainerUtil.emptyList();
|
||||
|
||||
List<TextRange> cachedChangedLines = getCachedChangedLines(project, document);
|
||||
if (cachedChangedLines != null) {
|
||||
return cachedChangedLines;
|
||||
}
|
||||
|
||||
if (ApplicationManager.getApplication().isUnitTestMode()) {
|
||||
String testContent = file.getUserData(TEST_REVISION_CONTENT);
|
||||
CharSequence testContent = file.getUserData(TEST_REVISION_CONTENT);
|
||||
if (testContent != null) {
|
||||
return calculateChangedTextRanges(file.getProject(), file, testContent);
|
||||
return calculateChangedTextRanges(document, testContent);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -270,17 +257,12 @@ public class FormatChangedTextUtil {
|
||||
}
|
||||
|
||||
String contentFromVcs = getRevisionedContentFrom(change);
|
||||
return contentFromVcs != null ? calculateChangedTextRanges(project, file, contentFromVcs)
|
||||
return contentFromVcs != null ? calculateChangedTextRanges(document, contentFromVcs)
|
||||
: ContainerUtil.<TextRange>emptyList();
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private static List<TextRange> getCachedChangedLines(@NotNull Project project, @NotNull PsiFile file) {
|
||||
Document document = PsiDocumentManager.getInstance(project).getDocument(file);
|
||||
if (document == null) {
|
||||
return ContainerUtil.emptyList();
|
||||
}
|
||||
|
||||
private static List<TextRange> getCachedChangedLines(@NotNull Project project, @NotNull Document document) {
|
||||
LineStatusTracker tracker = LineStatusTrackerManager.getInstance(project).getLineStatusTracker(document);
|
||||
if (tracker != null) {
|
||||
List<Range> ranges = tracker.getRanges();
|
||||
@@ -307,19 +289,49 @@ public class FormatChangedTextUtil {
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private static List<TextRange> calculateChangedTextRanges(@NotNull Project project,
|
||||
@NotNull PsiFile file,
|
||||
@NotNull String contentFromVcs) throws FilesTooBigForDiffException
|
||||
protected static List<TextRange> calculateChangedTextRanges(@NotNull Document document,
|
||||
@NotNull CharSequence contentFromVcs) throws FilesTooBigForDiffException
|
||||
{
|
||||
return getChangedTextRanges(document, getRanges(document, contentFromVcs));
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private static List<Range> getRanges(@NotNull Document document,
|
||||
@NotNull CharSequence contentFromVcs) throws FilesTooBigForDiffException
|
||||
{
|
||||
Document documentFromVcs = ((EditorFactoryImpl)EditorFactory.getInstance()).createDocument(contentFromVcs, true, false);
|
||||
Document document = PsiDocumentManager.getInstance(project).getDocument(file);
|
||||
return new RangesBuilder(document, documentFromVcs).getRanges();
|
||||
}
|
||||
|
||||
if (document == null) {
|
||||
return ContainerUtil.emptyList();
|
||||
protected static int calculateChangedLinesNumber(@NotNull Document document, @NotNull CharSequence contentFromVcs) {
|
||||
try {
|
||||
List<Range> changedRanges = getRanges(document, contentFromVcs);
|
||||
int linesChanges = 0;
|
||||
for (Range range : changedRanges) {
|
||||
linesChanges += countLines(range);
|
||||
}
|
||||
return linesChanges;
|
||||
} catch (FilesTooBigForDiffException e) {
|
||||
LOG.info("File too big, can not calculate changed lines number");
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
private static int countLines(Range range) {
|
||||
byte rangeType = range.getType();
|
||||
if (rangeType == Range.MODIFIED) {
|
||||
int currentChangedLines = range.getLine2() - range.getLine1();
|
||||
int revisionLinesChanged = range.getVcsLine2() - range.getVcsLine1();
|
||||
return Math.max(currentChangedLines, revisionLinesChanged);
|
||||
}
|
||||
else if (rangeType == Range.DELETED) {
|
||||
return range.getVcsLine2() - range.getVcsLine1();
|
||||
}
|
||||
else if (rangeType == Range.INSERTED) {
|
||||
return range.getLine2() - range.getLine1();
|
||||
}
|
||||
|
||||
List<Range> changedRanges = new RangesBuilder(document, documentFromVcs).getRanges();
|
||||
return getChangedTextRanges(document, changedRanges);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
|
||||
+85
@@ -0,0 +1,85 @@
|
||||
/*
|
||||
* Copyright 2000-2014 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.codeInsight.actions;
|
||||
|
||||
import com.intellij.ide.util.PropertiesComponent;
|
||||
import com.intellij.lang.Language;
|
||||
import com.intellij.psi.PsiFile;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
public class LastRunReformatCodeOptionsProvider {
|
||||
|
||||
private static final String OPTIMIZE_IMPORTS_KEY = "LayoutCode.optimizeImports";
|
||||
private static final String REARRANGE_ENTRIES_KEY = "LayoutCode.rearrangeEntries";
|
||||
private static final String PROCESS_CHANGED_TEXT_KEY = "LayoutCode.processChangedText";
|
||||
|
||||
private final PropertiesComponent myPropertiesComponent;
|
||||
|
||||
public LastRunReformatCodeOptionsProvider(@NotNull PropertiesComponent propertiesComponent) {
|
||||
myPropertiesComponent = propertiesComponent;
|
||||
}
|
||||
|
||||
public ReformatCodeRunOptions getLastRunOptions(@NotNull PsiFile file) {
|
||||
Language language = file.getLanguage();
|
||||
|
||||
ReformatCodeRunOptions settings = new ReformatCodeRunOptions(getLastTextRangeType());
|
||||
settings.setOptimizeImports(getLastOptimizeImports());
|
||||
settings.setRearrangeCode(isRearrangeCode(language));
|
||||
|
||||
return settings;
|
||||
}
|
||||
|
||||
public void saveRearrangeState(@NotNull Language language, boolean value) {
|
||||
String key = getRearrangeCodeKeyFor(language);
|
||||
myPropertiesComponent.setValue(key, Boolean.toString(value));
|
||||
}
|
||||
|
||||
public void saveOptimizeImportsState(boolean value) {
|
||||
String optimizeImports = Boolean.toString(value);
|
||||
myPropertiesComponent.setValue(OPTIMIZE_IMPORTS_KEY, optimizeImports);
|
||||
}
|
||||
|
||||
public boolean getLastOptimizeImports() {
|
||||
return myPropertiesComponent.getBoolean(OPTIMIZE_IMPORTS_KEY, false);
|
||||
}
|
||||
|
||||
public TextRangeType getLastTextRangeType() {
|
||||
return myPropertiesComponent.getBoolean(PROCESS_CHANGED_TEXT_KEY, false) ? TextRangeType.VCS_CHANGED_TEXT : TextRangeType.WHOLE_FILE;
|
||||
}
|
||||
|
||||
public void saveProcessVcsChangedTextState(boolean value) {
|
||||
String processOnlyVcsChangedText = Boolean.toString(value);
|
||||
myPropertiesComponent.setValue(PROCESS_CHANGED_TEXT_KEY, processOnlyVcsChangedText);
|
||||
}
|
||||
|
||||
public void saveRearrangeCodeState(boolean value) {
|
||||
myPropertiesComponent.setValue(REARRANGE_ENTRIES_KEY, Boolean.toString(value));
|
||||
}
|
||||
|
||||
public boolean getLastRearrangeCode() {
|
||||
return myPropertiesComponent.getBoolean(REARRANGE_ENTRIES_KEY, false);
|
||||
}
|
||||
|
||||
public boolean isRearrangeCode(@NotNull Language language) {
|
||||
String key = getRearrangeCodeKeyFor(language);
|
||||
return myPropertiesComponent.getBoolean(key, false);
|
||||
}
|
||||
|
||||
private static String getRearrangeCodeKeyFor(@NotNull Language language) {
|
||||
return REARRANGE_ENTRIES_KEY + language.getDisplayName();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,135 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<form xmlns="http://www.intellij.com/uidesigner/form/" version="1" bind-to-class="com.intellij.codeInsight.actions.LayoutCodeDialog">
|
||||
<grid id="27dc6" binding="myButtonsPanel" layout-manager="GridLayoutManager" row-count="3" column-count="5" same-size-horizontally="false" same-size-vertically="false" hgap="-1" vgap="-1">
|
||||
<margin top="0" left="0" bottom="0" right="0"/>
|
||||
<constraints>
|
||||
<xy x="20" y="20" width="472" height="400"/>
|
||||
</constraints>
|
||||
<properties/>
|
||||
<border type="none"/>
|
||||
<children>
|
||||
<vspacer id="52898">
|
||||
<constraints>
|
||||
<grid row="2" column="3" row-span="1" col-span="1" vsize-policy="6" hsize-policy="1" anchor="0" fill="2" indent="0" use-parent-layout="false"/>
|
||||
</constraints>
|
||||
</vspacer>
|
||||
<component id="8ca39" class="com.intellij.openapi.ui.Splitter">
|
||||
<constraints>
|
||||
<grid row="1" column="4" row-span="1" col-span="1" vsize-policy="3" hsize-policy="3" anchor="0" fill="0" indent="0" use-parent-layout="false"/>
|
||||
</constraints>
|
||||
<properties/>
|
||||
</component>
|
||||
<grid id="91e0a" binding="myActionsPanel" layout-manager="GridLayoutManager" row-count="3" column-count="1" same-size-horizontally="false" same-size-vertically="false" hgap="-1" vgap="-1">
|
||||
<margin top="0" left="0" bottom="0" right="0"/>
|
||||
<constraints>
|
||||
<grid row="1" column="1" row-span="1" col-span="1" vsize-policy="3" hsize-policy="3" anchor="0" fill="3" indent="0" use-parent-layout="false"/>
|
||||
</constraints>
|
||||
<properties/>
|
||||
<border type="none"/>
|
||||
<children>
|
||||
<component id="9d93" class="javax.swing.JCheckBox" binding="myOptimizeImportsCb" default-binding="true">
|
||||
<constraints>
|
||||
<grid row="0" column="0" row-span="1" col-span="1" vsize-policy="0" hsize-policy="3" anchor="8" fill="0" indent="0" use-parent-layout="false"/>
|
||||
</constraints>
|
||||
<properties>
|
||||
<margin top="0" left="0" bottom="0" right="0"/>
|
||||
<text value="&Optimize imports"/>
|
||||
</properties>
|
||||
</component>
|
||||
<vspacer id="2d364">
|
||||
<constraints>
|
||||
<grid row="2" column="0" row-span="1" col-span="1" vsize-policy="6" hsize-policy="1" anchor="0" fill="2" indent="0" use-parent-layout="false"/>
|
||||
</constraints>
|
||||
</vspacer>
|
||||
<component id="a291" class="javax.swing.JCheckBox" binding="myRearrangeCodeCb" default-binding="true">
|
||||
<constraints>
|
||||
<grid row="1" column="0" row-span="1" col-span="1" vsize-policy="0" hsize-policy="3" anchor="8" fill="0" indent="0" use-parent-layout="false"/>
|
||||
</constraints>
|
||||
<properties>
|
||||
<margin top="0" left="0" bottom="0" right="0"/>
|
||||
<text value="Rearra&nge code"/>
|
||||
</properties>
|
||||
</component>
|
||||
</children>
|
||||
</grid>
|
||||
<grid id="b1a5c" binding="myScopePanel" layout-manager="GridLayoutManager" row-count="4" column-count="2" same-size-horizontally="false" same-size-vertically="false" hgap="-1" vgap="-1">
|
||||
<margin top="0" left="0" bottom="0" right="0"/>
|
||||
<constraints>
|
||||
<grid row="1" column="0" row-span="1" col-span="1" vsize-policy="3" hsize-policy="3" anchor="0" fill="3" indent="0" use-parent-layout="false"/>
|
||||
</constraints>
|
||||
<properties/>
|
||||
<border type="none"/>
|
||||
<children>
|
||||
<component id="cea7f" class="javax.swing.JRadioButton" binding="myOnlyVCSChangedTextRb" default-binding="true">
|
||||
<constraints>
|
||||
<grid row="0" column="0" row-span="1" col-span="1" vsize-policy="0" hsize-policy="3" anchor="8" fill="0" indent="0" use-parent-layout="false"/>
|
||||
</constraints>
|
||||
<properties>
|
||||
<margin top="0" left="0" bottom="0" right="0"/>
|
||||
<text value="Only &VCS changed text"/>
|
||||
</properties>
|
||||
</component>
|
||||
<hspacer id="6a094">
|
||||
<constraints>
|
||||
<grid row="0" column="1" row-span="1" col-span="1" vsize-policy="1" hsize-policy="6" anchor="0" fill="1" indent="0" use-parent-layout="false"/>
|
||||
</constraints>
|
||||
</hspacer>
|
||||
<vspacer id="467fa">
|
||||
<constraints>
|
||||
<grid row="3" column="0" row-span="1" col-span="1" vsize-policy="6" hsize-policy="1" anchor="0" fill="2" indent="0" use-parent-layout="false"/>
|
||||
</constraints>
|
||||
</vspacer>
|
||||
<component id="27301" class="javax.swing.JRadioButton" binding="mySelectedTextRadioButton" default-binding="true">
|
||||
<constraints>
|
||||
<grid row="1" column="0" row-span="1" col-span="1" vsize-policy="0" hsize-policy="3" anchor="8" fill="0" indent="0" use-parent-layout="false"/>
|
||||
</constraints>
|
||||
<properties>
|
||||
<margin top="0" left="0" bottom="0" right="0"/>
|
||||
<text value="&Selected text"/>
|
||||
</properties>
|
||||
</component>
|
||||
<component id="2eea6" class="javax.swing.JRadioButton" binding="myWholeFileRadioButton" default-binding="true">
|
||||
<constraints>
|
||||
<grid row="2" column="0" row-span="1" col-span="1" vsize-policy="0" hsize-policy="3" anchor="8" fill="0" indent="0" use-parent-layout="false"/>
|
||||
</constraints>
|
||||
<properties>
|
||||
<margin top="0" left="0" bottom="0" right="0"/>
|
||||
<text value="&Whole file"/>
|
||||
</properties>
|
||||
</component>
|
||||
</children>
|
||||
</grid>
|
||||
<component id="38fdd" class="javax.swing.JLabel">
|
||||
<constraints>
|
||||
<grid row="0" column="0" row-span="1" col-span="1" vsize-policy="0" hsize-policy="0" anchor="8" fill="0" indent="0" use-parent-layout="false"/>
|
||||
</constraints>
|
||||
<properties>
|
||||
<text value="Scope:"/>
|
||||
</properties>
|
||||
</component>
|
||||
<component id="1fda7" class="javax.swing.JLabel">
|
||||
<constraints>
|
||||
<grid row="0" column="1" row-span="1" col-span="1" vsize-policy="0" hsize-policy="0" anchor="8" fill="0" indent="0" use-parent-layout="false"/>
|
||||
</constraints>
|
||||
<properties>
|
||||
<text value="Optional:"/>
|
||||
</properties>
|
||||
</component>
|
||||
<hspacer id="b6b1d">
|
||||
<constraints>
|
||||
<grid row="1" column="2" row-span="1" col-span="1" vsize-policy="1" hsize-policy="6" anchor="0" fill="1" indent="0" use-parent-layout="false"/>
|
||||
</constraints>
|
||||
</hspacer>
|
||||
</children>
|
||||
</grid>
|
||||
<buttonGroups>
|
||||
<group name="myGroup1">
|
||||
<member id="e5942"/>
|
||||
<member id="4a767"/>
|
||||
<member id="2b374"/>
|
||||
<member id="27301"/>
|
||||
<member id="2eea6"/>
|
||||
<member id="cea7f"/>
|
||||
</group>
|
||||
</buttonGroups>
|
||||
</form>
|
||||
@@ -16,279 +16,173 @@
|
||||
|
||||
package com.intellij.codeInsight.actions;
|
||||
|
||||
import com.intellij.CommonBundle;
|
||||
import com.intellij.codeInsight.CodeInsightBundle;
|
||||
import com.intellij.ide.util.PropertiesComponent;
|
||||
import com.intellij.lang.LanguageImportStatements;
|
||||
import com.intellij.openapi.editor.ex.EditorSettingsExternalizable;
|
||||
import com.intellij.openapi.help.HelpManager;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.ui.DialogWrapper;
|
||||
import com.intellij.psi.PsiDirectory;
|
||||
import com.intellij.psi.PsiFile;
|
||||
import com.intellij.psi.codeStyle.CodeStyleSettingsManager;
|
||||
import com.intellij.psi.codeStyle.CommonCodeStyleSettings;
|
||||
import com.intellij.psi.codeStyle.arrangement.Rearranger;
|
||||
import com.intellij.psi.search.SearchScope;
|
||||
import com.intellij.testFramework.LightVirtualFile;
|
||||
import com.intellij.vcsUtil.VcsUtil;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import javax.swing.*;
|
||||
import java.awt.*;
|
||||
import java.awt.event.ActionEvent;
|
||||
import java.awt.event.ActionListener;
|
||||
|
||||
public class LayoutCodeDialog extends DialogWrapper implements LayoutCodeOptions {
|
||||
public class LayoutCodeDialog extends DialogWrapper {
|
||||
@NotNull private final Project myProject;
|
||||
@Nullable private final PsiFile myFile;
|
||||
@Nullable private final PsiDirectory myDirectory;
|
||||
private final Boolean myTextSelected;
|
||||
@NotNull private final PsiFile myFile;
|
||||
|
||||
private JRadioButton myRbFile;
|
||||
private JRadioButton myRbSelectedText;
|
||||
private JRadioButton myRbDirectory;
|
||||
private JCheckBox myCbIncludeSubdirs;
|
||||
private JCheckBox myCbOptimizeImports;
|
||||
private JCheckBox myCbArrangeEntries;
|
||||
private JCheckBox myCbOnlyVcsChangedRegions;
|
||||
private JCheckBox myDoNotAskMeCheckBox;
|
||||
private final boolean myTextSelected;
|
||||
|
||||
private final String myHelpId;
|
||||
@Nullable private CommonCodeStyleSettings myCommonSettings;
|
||||
private boolean myRearrangeAlwaysEnabled;
|
||||
private final LastRunReformatCodeOptionsProvider myLastRunOptions;
|
||||
|
||||
private final boolean myOptimizeImportProcessorsForFileLanguageExists;
|
||||
private final boolean myRearrangerProcessorsForFileLanguageExists;
|
||||
private final boolean myFileHasChanges;
|
||||
private JPanel myButtonsPanel;
|
||||
|
||||
private boolean myOptimizeImportsSelected;
|
||||
private boolean myFormatOnlyVCSChangedRegionsSelected;
|
||||
private boolean myDoNotShowDialogSelected;
|
||||
private boolean myRearrangeEntriesSelected;
|
||||
private JCheckBox myOptimizeImportsCb;
|
||||
private JCheckBox myRearrangeCodeCb;
|
||||
|
||||
private JRadioButton myOnlyVCSChangedTextRb;
|
||||
private JRadioButton mySelectedTextRadioButton;
|
||||
private JRadioButton myWholeFileRadioButton;
|
||||
|
||||
public LayoutCodeDialog(@NotNull Project project,
|
||||
@NotNull String title,
|
||||
@Nullable PsiFile file,
|
||||
@Nullable PsiDirectory directory,
|
||||
Boolean isTextSelected,
|
||||
private JPanel myActionsPanel;
|
||||
private JPanel myScopePanel;
|
||||
|
||||
private LayoutCodeOptions myRunOptions;
|
||||
|
||||
public LayoutCodeDialog(@NotNull Project project,
|
||||
@NotNull PsiFile file,
|
||||
boolean textSelected,
|
||||
final String helpId) {
|
||||
super(project, true);
|
||||
myFile = file;
|
||||
myProject = project;
|
||||
myDirectory = directory;
|
||||
myTextSelected = isTextSelected;
|
||||
myTextSelected = textSelected;
|
||||
myHelpId = helpId;
|
||||
|
||||
myOptimizeImportProcessorsForFileLanguageExists = myFile != null && !LanguageImportStatements.INSTANCE.forFile(myFile).isEmpty();
|
||||
myRearrangerProcessorsForFileLanguageExists = myFile != null && Rearranger.EXTENSION.forLanguage(myFile.getLanguage()) != null;
|
||||
myFileHasChanges = myFile != null && FormatChangedTextUtil.hasChanges(myFile);
|
||||
|
||||
if (myFile != null) myCommonSettings = CodeStyleSettingsManager.getSettings(myProject).getCommonSettings(myFile.getLanguage());
|
||||
myRearrangeAlwaysEnabled = myCommonSettings != null
|
||||
&& myCommonSettings.isForceArrangeMenuAvailable()
|
||||
&& myCommonSettings.FORCE_REARRANGE_MODE == CommonCodeStyleSettings.REARRANGE_ALWAYS;
|
||||
myLastRunOptions = new LastRunReformatCodeOptionsProvider(PropertiesComponent.getInstance());
|
||||
myRunOptions = createOptionsBundledOnDialog();
|
||||
|
||||
setOKButtonText(CodeInsightBundle.message("reformat.code.accept.button.text"));
|
||||
setTitle(title);
|
||||
setTitle("Reformat File: " + file.getName());
|
||||
|
||||
init();
|
||||
myHelpId = helpId;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void init() {
|
||||
super.init();
|
||||
|
||||
loadCbsStates();
|
||||
setUpInitialSelection();
|
||||
|
||||
myRbFile.addActionListener(new ActionListener() {
|
||||
@Override
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
saveEnabledCbsSelectedState();
|
||||
setUpCbsStateForFileFormatting();
|
||||
}
|
||||
});
|
||||
|
||||
myRbDirectory.addActionListener(new ActionListener() {
|
||||
@Override
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
saveEnabledCbsSelectedState();
|
||||
setUpCbsStatesForDirectoryFormatting();
|
||||
}
|
||||
});
|
||||
|
||||
myRbSelectedText.addActionListener(new ActionListener() {
|
||||
@Override
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
saveEnabledCbsSelectedState();
|
||||
setUpCbsStatesForSelectedTextFormatting();
|
||||
}
|
||||
});
|
||||
setUpActions();
|
||||
setUpTextRangeMode();
|
||||
}
|
||||
|
||||
private void setUpInitialSelection() {
|
||||
if (myTextSelected == Boolean.TRUE) {
|
||||
myRbSelectedText.setSelected(true);
|
||||
setUpCbsStatesForSelectedTextFormatting();
|
||||
|
||||
private void setUpTextRangeMode() {
|
||||
mySelectedTextRadioButton.setEnabled(myTextSelected);
|
||||
if (!myTextSelected) {
|
||||
mySelectedTextRadioButton.setToolTipText("No text selected in editor");
|
||||
}
|
||||
|
||||
final boolean fileHasChanges = FormatChangedTextUtil.hasChanges(myFile);
|
||||
if (myFile.getVirtualFile() instanceof LightVirtualFile) {
|
||||
myOnlyVCSChangedTextRb.setVisible(false);
|
||||
}
|
||||
else {
|
||||
if (myFile != null) {
|
||||
myRbFile.setSelected(true);
|
||||
setUpCbsStateForFileFormatting();
|
||||
myOnlyVCSChangedTextRb.setEnabled(fileHasChanges);
|
||||
if (!fileHasChanges) {
|
||||
String hint = getChangesNotAvailableHint();
|
||||
if (hint != null) myOnlyVCSChangedTextRb.setToolTipText(hint);
|
||||
}
|
||||
}
|
||||
|
||||
myWholeFileRadioButton.setEnabled(true);
|
||||
|
||||
if (myTextSelected) {
|
||||
mySelectedTextRadioButton.setSelected(true);
|
||||
}
|
||||
else {
|
||||
boolean lastRunProcessedChangedText = myLastRunOptions.getLastTextRangeType() == TextRangeType.VCS_CHANGED_TEXT;
|
||||
if (lastRunProcessedChangedText && fileHasChanges) {
|
||||
myOnlyVCSChangedTextRb.setSelected(true);
|
||||
}
|
||||
else {
|
||||
myRbDirectory.setSelected(true);
|
||||
setUpCbsStatesForDirectoryFormatting();
|
||||
myWholeFileRadioButton.setSelected(true);
|
||||
}
|
||||
}
|
||||
myCbIncludeSubdirs.setSelected(true);
|
||||
}
|
||||
|
||||
private void loadCbsStates() {
|
||||
myOptimizeImportsSelected = PropertiesComponent.getInstance().getBoolean(LayoutCodeConstants.OPTIMIZE_IMPORTS_KEY, false);
|
||||
myRearrangeEntriesSelected = myRearrangeAlwaysEnabled || ReformatCodeAction.getLastSavedRearrangeCbState(myProject, myFile);
|
||||
myFormatOnlyVCSChangedRegionsSelected = PropertiesComponent.getInstance().getBoolean(LayoutCodeConstants.PROCESS_CHANGED_TEXT_KEY, false);
|
||||
}
|
||||
private void setUpActions() {
|
||||
boolean canOptimizeImports = !LanguageImportStatements.INSTANCE.forFile(myFile).isEmpty();
|
||||
myOptimizeImportsCb.setVisible(canOptimizeImports);
|
||||
if (canOptimizeImports) {
|
||||
myOptimizeImportsCb.setSelected(myLastRunOptions.getLastOptimizeImports());
|
||||
}
|
||||
|
||||
private void saveEnabledCbsSelectedState() {
|
||||
if (myCbArrangeEntries.isEnabled()) {
|
||||
myRearrangeEntriesSelected = myCbArrangeEntries.isSelected();
|
||||
}
|
||||
if (myCbOptimizeImports.isEnabled()) {
|
||||
myOptimizeImportsSelected = myCbOptimizeImports.isSelected();
|
||||
}
|
||||
if (myCbOnlyVcsChangedRegions.isEnabled()) {
|
||||
myFormatOnlyVCSChangedRegionsSelected = myCbOnlyVcsChangedRegions.isSelected();
|
||||
}
|
||||
if (myDoNotAskMeCheckBox.isEnabled()) {
|
||||
myDoNotShowDialogSelected = myDoNotAskMeCheckBox.isSelected();
|
||||
boolean canRearrangeCode = Rearranger.EXTENSION.forLanguage(myFile.getLanguage()) != null;
|
||||
myRearrangeCodeCb.setVisible(canRearrangeCode);
|
||||
if (canRearrangeCode) {
|
||||
myRearrangeCodeCb.setSelected(myLastRunOptions.isRearrangeCode(myFile.getLanguage()));
|
||||
}
|
||||
}
|
||||
|
||||
private void setUpCbsStateForFileFormatting() {
|
||||
myCbOptimizeImports.setEnabled(myOptimizeImportProcessorsForFileLanguageExists);
|
||||
myCbOptimizeImports.setSelected(myOptimizeImportProcessorsForFileLanguageExists && myOptimizeImportsSelected);
|
||||
|
||||
myCbArrangeEntries.setEnabled(myRearrangerProcessorsForFileLanguageExists);
|
||||
myCbArrangeEntries.setSelected(myRearrangerProcessorsForFileLanguageExists && myRearrangeEntriesSelected);
|
||||
|
||||
myCbOnlyVcsChangedRegions.setEnabled(myFileHasChanges);
|
||||
myCbOnlyVcsChangedRegions.setSelected(myFileHasChanges && myFormatOnlyVCSChangedRegionsSelected);
|
||||
|
||||
myDoNotAskMeCheckBox.setEnabled(true);
|
||||
myDoNotAskMeCheckBox.setSelected(myDoNotShowDialogSelected);
|
||||
|
||||
myCbIncludeSubdirs.setEnabled(false);
|
||||
@Nullable
|
||||
private String getChangesNotAvailableHint() {
|
||||
if (!VcsUtil.isFileUnderVcs(myProject, VcsUtil.getFilePath(myFile.getVirtualFile()))) {
|
||||
return "File not under VCS root";
|
||||
}
|
||||
else if (!FormatChangedTextUtil.hasChanges(myFile)) {
|
||||
return "File was not changed since last revision";
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private void setUpCbsStatesForDirectoryFormatting() {
|
||||
myCbOptimizeImports.setEnabled(true);
|
||||
myCbOptimizeImports.setSelected(myOptimizeImportsSelected);
|
||||
private void saveCurrentConfiguration() {
|
||||
if (myOptimizeImportsCb.isEnabled()) {
|
||||
myLastRunOptions.saveOptimizeImportsState(myRunOptions.isOptimizeImports());
|
||||
}
|
||||
if (myRearrangeCodeCb.isEnabled()) {
|
||||
myLastRunOptions.saveRearrangeState(myFile.getLanguage(), myRunOptions.isRearrangeCode());
|
||||
}
|
||||
|
||||
myCbArrangeEntries.setEnabled(true);
|
||||
myCbArrangeEntries.setSelected(myRearrangeEntriesSelected);
|
||||
|
||||
myCbOnlyVcsChangedRegions.setEnabled(myDirectory != null && FormatChangedTextUtil.hasChanges(myDirectory));
|
||||
myCbOnlyVcsChangedRegions.setSelected(false);
|
||||
|
||||
myDoNotAskMeCheckBox.setEnabled(false);
|
||||
myDoNotAskMeCheckBox.setSelected(false);
|
||||
|
||||
myCbIncludeSubdirs.setEnabled(true);
|
||||
if (!mySelectedTextRadioButton.isSelected()) {
|
||||
myLastRunOptions.saveProcessVcsChangedTextState(myOnlyVCSChangedTextRb.isSelected());
|
||||
}
|
||||
}
|
||||
|
||||
private void setUpCbsStatesForSelectedTextFormatting() {
|
||||
myCbOptimizeImports.setEnabled(false);
|
||||
myCbOptimizeImports.setSelected(false);
|
||||
@NotNull
|
||||
private LayoutCodeOptions createOptionsBundledOnDialog() {
|
||||
return new LayoutCodeOptions() {
|
||||
@Override
|
||||
public TextRangeType getTextRangeType() {
|
||||
if (myOnlyVCSChangedTextRb.isSelected()) {
|
||||
return TextRangeType.VCS_CHANGED_TEXT;
|
||||
}
|
||||
if (mySelectedTextRadioButton.isSelected()) {
|
||||
return TextRangeType.SELECTED_TEXT;
|
||||
}
|
||||
return TextRangeType.WHOLE_FILE;
|
||||
}
|
||||
|
||||
myCbArrangeEntries.setEnabled(true);
|
||||
myCbArrangeEntries.setSelected(myRearrangeEntriesSelected);
|
||||
@Override
|
||||
public boolean isRearrangeCode() {
|
||||
return myRearrangeCodeCb.isEnabled() && myRearrangeCodeCb.isSelected();
|
||||
}
|
||||
|
||||
myCbOnlyVcsChangedRegions.setEnabled(false);
|
||||
myCbOnlyVcsChangedRegions.setSelected(false);
|
||||
|
||||
myDoNotAskMeCheckBox.setEnabled(true);
|
||||
myDoNotAskMeCheckBox.setSelected(myDoNotShowDialogSelected);
|
||||
|
||||
myCbIncludeSubdirs.setEnabled(false);
|
||||
@Override
|
||||
public boolean isOptimizeImports() {
|
||||
return myOptimizeImportsCb.isEnabled() && myOptimizeImportsCb.isSelected();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
protected JComponent createCenterPanel() {
|
||||
JPanel panel = new JPanel(new GridBagLayout());
|
||||
panel.setBorder(BorderFactory.createEmptyBorder(4, 8, 8, 0));
|
||||
GridBagConstraints gbConstraints = new GridBagConstraints();
|
||||
gbConstraints.gridy = 0;
|
||||
gbConstraints.gridx = 0;
|
||||
gbConstraints.gridwidth = 3;
|
||||
gbConstraints.gridheight = 1;
|
||||
gbConstraints.weightx = 1;
|
||||
|
||||
gbConstraints.fill = GridBagConstraints.BOTH;
|
||||
gbConstraints.insets = new Insets(0, 0, 0, 0);
|
||||
|
||||
myRbFile = new JRadioButton(CodeInsightBundle.message("process.scope.file",
|
||||
(myFile != null ? "'" + myFile.getVirtualFile().getPresentableUrl() + "'" : "")));
|
||||
panel.add(myRbFile, gbConstraints);
|
||||
|
||||
myRbSelectedText = new JRadioButton(CodeInsightBundle.message("reformat.option.selected.text"));
|
||||
if (myTextSelected != null) {
|
||||
gbConstraints.gridy++;
|
||||
gbConstraints.insets = new Insets(0, 0, 0, 0);
|
||||
panel.add(myRbSelectedText, gbConstraints);
|
||||
}
|
||||
|
||||
myRbDirectory = new JRadioButton();
|
||||
myCbIncludeSubdirs = new JCheckBox(CodeInsightBundle.message("reformat.option.include.subdirectories"));
|
||||
if (myDirectory != null) {
|
||||
myRbDirectory.setText(CodeInsightBundle.message("reformat.option.all.files.in.directory",
|
||||
myDirectory.getVirtualFile().getPresentableUrl()));
|
||||
gbConstraints.gridy++;
|
||||
gbConstraints.insets = new Insets(0, 0, 0, 0);
|
||||
panel.add(myRbDirectory, gbConstraints);
|
||||
|
||||
if (myDirectory.getSubdirectories().length > 0) {
|
||||
gbConstraints.gridy++;
|
||||
gbConstraints.insets = new Insets(0, 20, 0, 0);
|
||||
panel.add(myCbIncludeSubdirs, gbConstraints);
|
||||
}
|
||||
}
|
||||
|
||||
myCbOptimizeImports = new JCheckBox(CodeInsightBundle.message("reformat.option.optimize.imports"));
|
||||
if (myTextSelected != null && LanguageImportStatements.INSTANCE.hasAnyExtensions()) {
|
||||
gbConstraints.gridy++;
|
||||
gbConstraints.insets = new Insets(0, 0, 0, 0);
|
||||
panel.add(myCbOptimizeImports, gbConstraints);
|
||||
}
|
||||
|
||||
myCbArrangeEntries = new JCheckBox(CodeInsightBundle.message("reformat.option.rearrange.entries"));
|
||||
if (myDirectory != null || myFile != null && Rearranger.EXTENSION.forLanguage(myFile.getLanguage()) != null)
|
||||
{
|
||||
gbConstraints.gridy++;
|
||||
gbConstraints.insets = new Insets(0, 0, 0, 0);
|
||||
panel.add(myCbArrangeEntries, gbConstraints);
|
||||
}
|
||||
|
||||
myCbOnlyVcsChangedRegions = new JCheckBox(CodeInsightBundle.message("reformat.option.vcs.changed.region"));
|
||||
gbConstraints.gridy++;
|
||||
panel.add(myCbOnlyVcsChangedRegions, gbConstraints);
|
||||
|
||||
ButtonGroup buttonGroup = new ButtonGroup();
|
||||
buttonGroup.add(myRbFile);
|
||||
buttonGroup.add(myRbSelectedText);
|
||||
buttonGroup.add(myRbDirectory);
|
||||
|
||||
myRbFile.setEnabled(myFile != null);
|
||||
myRbSelectedText.setEnabled(myTextSelected == Boolean.TRUE);
|
||||
|
||||
return panel;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected JComponent createSouthPanel() {
|
||||
JComponent southPanel = super.createSouthPanel();
|
||||
myDoNotAskMeCheckBox = new JCheckBox(CommonBundle.message("dialog.options.do.not.show"));
|
||||
return DialogWrapper.addDoNotShowCheckBox(southPanel, myDoNotAskMeCheckBox);
|
||||
return myButtonsPanel;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@@ -302,81 +196,14 @@ public class LayoutCodeDialog extends DialogWrapper implements LayoutCodeOptions
|
||||
HelpManager.getInstance().invokeHelp(myHelpId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isProcessWholeFile() {
|
||||
return myRbFile.isSelected();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isProcessDirectory() {
|
||||
return myRbDirectory.isSelected();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isIncludeSubdirectories() {
|
||||
return myCbIncludeSubdirs.isSelected();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isOptimizeImports() {
|
||||
return myCbOptimizeImports.isSelected();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isRearrangeEntries() {
|
||||
return myCbArrangeEntries.isSelected();
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public String getFileTypeMask() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public SearchScope getSearchScope() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isProcessOnlyChangedText() {
|
||||
return myCbOnlyVcsChangedRegions.isEnabled() && myCbOnlyVcsChangedRegions.isSelected();
|
||||
}
|
||||
|
||||
public boolean isDoNotAskMe() {
|
||||
if (myDoNotAskMeCheckBox.isEnabled()) {
|
||||
return myDoNotAskMeCheckBox.isSelected();
|
||||
}
|
||||
else {
|
||||
return !EditorSettingsExternalizable.getInstance().getOptions().SHOW_REFORMAT_DIALOG;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void doOKAction() {
|
||||
super.doOKAction();
|
||||
persistEnabledCbsStates();
|
||||
saveCurrentConfiguration();
|
||||
}
|
||||
|
||||
private void persistEnabledCbsStates() {
|
||||
if (myCbOptimizeImports.isEnabled()) {
|
||||
String optimizeImports = Boolean.toString(myCbOptimizeImports.isSelected());
|
||||
PropertiesComponent.getInstance().setValue(LayoutCodeConstants.OPTIMIZE_IMPORTS_KEY, optimizeImports);
|
||||
}
|
||||
if (myCbOnlyVcsChangedRegions.isEnabled()) {
|
||||
String formatVcsChangedRegions = Boolean.toString(myCbOnlyVcsChangedRegions.isSelected());
|
||||
PropertiesComponent.getInstance().setValue(LayoutCodeConstants.PROCESS_CHANGED_TEXT_KEY, formatVcsChangedRegions);
|
||||
}
|
||||
if (myCbArrangeEntries.isEnabled()) {
|
||||
saveRearrangeCbState(myCbArrangeEntries.isSelected());
|
||||
}
|
||||
public LayoutCodeOptions getRunOptions() {
|
||||
return myRunOptions;
|
||||
}
|
||||
|
||||
private void saveRearrangeCbState(boolean isSelected) {
|
||||
if (myFile != null)
|
||||
LayoutCodeSettingsStorage.saveRearrangeEntriesOptionFor(myProject, myFile.getLanguage(), isSelected);
|
||||
else
|
||||
LayoutCodeSettingsStorage.saveRearrangeEntriesOptionFor(myProject, isSelected);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,58 @@
|
||||
/*
|
||||
* Copyright 2000-2015 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.codeInsight.actions;
|
||||
|
||||
public class LayoutCodeInfoCollector {
|
||||
|
||||
private String optimizeImportsNotification = null;
|
||||
private String reformatCodeNotification = null;
|
||||
private String rearrangeCodeNotification = null;
|
||||
|
||||
public String getOptimizeImportsNotification() {
|
||||
return optimizeImportsNotification;
|
||||
}
|
||||
|
||||
public void setOptimizeImportsNotification(String optimizeImportsNotification) {
|
||||
this.optimizeImportsNotification = optimizeImportsNotification;
|
||||
}
|
||||
|
||||
public String getReformatCodeNotification() {
|
||||
return reformatCodeNotification;
|
||||
}
|
||||
|
||||
public void setReformatCodeNotification(String reformatCodeNotification) {
|
||||
this.reformatCodeNotification = reformatCodeNotification;
|
||||
}
|
||||
|
||||
public String getRearrangeCodeNotification() {
|
||||
return rearrangeCodeNotification;
|
||||
}
|
||||
|
||||
public void setRearrangeCodeNotification(String rearrangeCodeNotification) {
|
||||
this.rearrangeCodeNotification = rearrangeCodeNotification;
|
||||
}
|
||||
|
||||
public boolean hasReformatOrRearrangeNotification() {
|
||||
return rearrangeCodeNotification != null
|
||||
|| reformatCodeNotification != null;
|
||||
}
|
||||
|
||||
public boolean isEmpty() {
|
||||
return optimizeImportsNotification == null
|
||||
&& rearrangeCodeNotification == null
|
||||
&& reformatCodeNotification == null;
|
||||
}
|
||||
}
|
||||
@@ -15,10 +15,14 @@
|
||||
*/
|
||||
package com.intellij.codeInsight.actions;
|
||||
|
||||
public interface LayoutCodeOptions extends DirectoryFormattingOptions {
|
||||
public interface LayoutCodeOptions extends OptionalReformatActions {
|
||||
|
||||
boolean isProcessWholeFile();
|
||||
|
||||
boolean isProcessDirectory();
|
||||
TextRangeType getTextRangeType();
|
||||
|
||||
}
|
||||
|
||||
enum TextRangeType {
|
||||
VCS_CHANGED_TEXT,
|
||||
SELECTED_TEXT,
|
||||
WHOLE_FILE
|
||||
}
|
||||
|
||||
-50
@@ -1,50 +0,0 @@
|
||||
/*
|
||||
* Copyright 2000-2013 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.codeInsight.actions;
|
||||
|
||||
import com.intellij.ide.util.PropertiesComponent;
|
||||
import com.intellij.lang.Language;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
public class LayoutCodeSettingsStorage {
|
||||
|
||||
private LayoutCodeSettingsStorage() {
|
||||
}
|
||||
|
||||
public static void saveRearrangeEntriesOptionFor(@NotNull Project project, @NotNull Language language, boolean value) {
|
||||
String key = getRearrangeEntriesKeyForLanguage(language);
|
||||
PropertiesComponent.getInstance(project).setValue(key, Boolean.toString(value));
|
||||
}
|
||||
|
||||
public static void saveRearrangeEntriesOptionFor(@NotNull Project project, boolean value) {
|
||||
PropertiesComponent.getInstance(project).setValue(LayoutCodeConstants.REARRANGE_ENTRIES_KEY, Boolean.toString(value));
|
||||
}
|
||||
|
||||
public static boolean getLastSavedRearrangeEntriesCbStateFor(@NotNull Project project) {
|
||||
return PropertiesComponent.getInstance(project).getBoolean(LayoutCodeConstants.REARRANGE_ENTRIES_KEY, false);
|
||||
}
|
||||
|
||||
public static boolean getLastSavedRearrangeEntriesCbStateFor(@NotNull Project project, @NotNull Language language) {
|
||||
String key = getRearrangeEntriesKeyForLanguage(language);
|
||||
return PropertiesComponent.getInstance(project).getBoolean(key, false);
|
||||
}
|
||||
|
||||
private static String getRearrangeEntriesKeyForLanguage(@NotNull Language language) {
|
||||
return LayoutCodeConstants.REARRANGE_ENTRIES_KEY + language.getDisplayName();
|
||||
}
|
||||
|
||||
}
|
||||
+15
-11
@@ -47,6 +47,7 @@ public class LayoutProjectCodeDialog extends DialogWrapper implements ReformatFi
|
||||
private final Project myProject;
|
||||
private final String myText;
|
||||
private final boolean myEnableOnlyVCSChangedTextCb;
|
||||
private final LastRunReformatCodeOptionsProvider myLastRunOptions;
|
||||
|
||||
private JLabel myTitle;
|
||||
protected JCheckBox myIncludeSubdirsCb;
|
||||
@@ -75,6 +76,7 @@ public class LayoutProjectCodeDialog extends DialogWrapper implements ReformatFi
|
||||
myText = text;
|
||||
myProject = project;
|
||||
myEnableOnlyVCSChangedTextCb = enableOnlyVCSChangedTextCb;
|
||||
myLastRunOptions = new LastRunReformatCodeOptionsProvider(PropertiesComponent.getInstance());
|
||||
|
||||
setOKButtonText(CodeInsightBundle.message("reformat.code.accept.button.text"));
|
||||
setTitle(title);
|
||||
@@ -100,11 +102,11 @@ public class LayoutProjectCodeDialog extends DialogWrapper implements ReformatFi
|
||||
}
|
||||
|
||||
private void restoreCbsStates() {
|
||||
myCbOptimizeImports.setSelected(PropertiesComponent.getInstance().getBoolean(LayoutCodeConstants.OPTIMIZE_IMPORTS_KEY, false));
|
||||
myCbRearrangeEntries.setSelected(LayoutCodeSettingsStorage.getLastSavedRearrangeEntriesCbStateFor(myProject));
|
||||
myCbOptimizeImports.setSelected(myLastRunOptions.getLastOptimizeImports());
|
||||
myCbRearrangeEntries.setSelected(myLastRunOptions.getLastRearrangeCode());
|
||||
myCbOnlyVcsChangedRegions.setEnabled(myEnableOnlyVCSChangedTextCb);
|
||||
myCbOnlyVcsChangedRegions.setSelected(
|
||||
myEnableOnlyVCSChangedTextCb && PropertiesComponent.getInstance().getBoolean(LayoutCodeConstants.PROCESS_CHANGED_TEXT_KEY, false)
|
||||
myEnableOnlyVCSChangedTextCb && myLastRunOptions.getLastTextRangeType() == TextRangeType.VCS_CHANGED_TEXT
|
||||
);
|
||||
}
|
||||
|
||||
@@ -177,7 +179,7 @@ public class LayoutProjectCodeDialog extends DialogWrapper implements ReformatFi
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isRearrangeEntries() {
|
||||
public boolean isRearrangeCode() {
|
||||
return myCbRearrangeEntries.isSelected();
|
||||
}
|
||||
|
||||
@@ -189,10 +191,10 @@ public class LayoutProjectCodeDialog extends DialogWrapper implements ReformatFi
|
||||
@Override
|
||||
protected void doOKAction() {
|
||||
super.doOKAction();
|
||||
PropertiesComponent.getInstance().setValue(LayoutCodeConstants.OPTIMIZE_IMPORTS_KEY, Boolean.toString(isOptimizeImports()));
|
||||
LayoutCodeSettingsStorage.saveRearrangeEntriesOptionFor(myProject, isRearrangeEntries());
|
||||
myLastRunOptions.saveOptimizeImportsState(isOptimizeImports());
|
||||
myLastRunOptions.saveRearrangeCodeState(isRearrangeCode());
|
||||
if (myEnableOnlyVCSChangedTextCb) {
|
||||
PropertiesComponent.getInstance().setValue(LayoutCodeConstants.PROCESS_CHANGED_TEXT_KEY, Boolean.toString(myCbOnlyVcsChangedRegions.isSelected()));
|
||||
myLastRunOptions.saveProcessVcsChangedTextState(getTextRangeType() == TextRangeType.VCS_CHANGED_TEXT);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -200,10 +202,6 @@ public class LayoutProjectCodeDialog extends DialogWrapper implements ReformatFi
|
||||
return myCbOptimizeImports.isSelected();
|
||||
}
|
||||
|
||||
public boolean isProcessOnlyChangedText() {
|
||||
return myCbOnlyVcsChangedRegions.isEnabled() && myCbOnlyVcsChangedRegions.isSelected();
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public String getFileTypeMask() {
|
||||
if (myEnableFileNameFilterCb.isSelected()) {
|
||||
@@ -232,4 +230,10 @@ public class LayoutProjectCodeDialog extends DialogWrapper implements ReformatFi
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public TextRangeType getTextRangeType() {
|
||||
return myCbOnlyVcsChangedRegions.isEnabled() && myCbOnlyVcsChangedRegions.isSelected()
|
||||
? TextRangeType.VCS_CHANGED_TEXT
|
||||
: TextRangeType.WHOLE_FILE;
|
||||
}
|
||||
}
|
||||
|
||||
+41
-24
@@ -17,11 +17,11 @@
|
||||
package com.intellij.codeInsight.actions;
|
||||
|
||||
import com.intellij.codeInsight.CodeInsightBundle;
|
||||
import com.intellij.ide.util.PropertiesComponent;
|
||||
import com.intellij.lang.LanguageImportStatements;
|
||||
import com.intellij.openapi.actionSystem.*;
|
||||
import com.intellij.openapi.application.ApplicationManager;
|
||||
import com.intellij.openapi.editor.Editor;
|
||||
import com.intellij.openapi.editor.ex.EditorSettingsExternalizable;
|
||||
import com.intellij.openapi.module.Module;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.ui.DialogWrapper;
|
||||
@@ -72,13 +72,16 @@ public class OptimizeImportsAction extends AnAction {
|
||||
|
||||
if (projectContext != null || moduleContext != null) {
|
||||
final String text;
|
||||
final boolean hasChanges;
|
||||
if (moduleContext != null) {
|
||||
text = CodeInsightBundle.message("process.scope.module", moduleContext.getName());
|
||||
hasChanges = FormatChangedTextUtil.hasChanges(moduleContext);
|
||||
}
|
||||
else {
|
||||
text = CodeInsightBundle.message("process.scope.project", projectContext.getPresentableUrl());
|
||||
hasChanges = FormatChangedTextUtil.hasChanges(projectContext);
|
||||
}
|
||||
DialogWrapper dialog = new OptimizeOnModuleDialog(project, text);
|
||||
DialogWrapper dialog = new OptimizeImportsDialog(project, text, hasChanges);
|
||||
if (!dialog.showAndGet()) {
|
||||
return;
|
||||
}
|
||||
@@ -106,29 +109,21 @@ public class OptimizeImportsAction extends AnAction {
|
||||
}
|
||||
}
|
||||
|
||||
boolean processDirectory;
|
||||
boolean includeSubdirectories;
|
||||
|
||||
if (ApplicationManager.getApplication().isUnitTestMode()) {
|
||||
includeSubdirectories = processDirectory = false;
|
||||
}
|
||||
else if (!EditorSettingsExternalizable.getInstance().getOptions().SHOW_OPIMIZE_IMPORTS_DIALOG && file != null) {
|
||||
includeSubdirectories = processDirectory = false;
|
||||
}
|
||||
else {
|
||||
final LayoutCodeDialog dialog =
|
||||
new LayoutCodeDialog(project, CodeInsightBundle.message("process.optimize.imports"), file, dir, null, HELP_ID);
|
||||
if (!dialog.showAndGet()) {
|
||||
boolean processDirectory = false;
|
||||
boolean processOnlyVcsChangedFiles = false;
|
||||
if (!ApplicationManager.getApplication().isUnitTestMode() && file == null && dir != null) {
|
||||
String message = CodeInsightBundle.message("process.scope.directory", dir.getName());
|
||||
OptimizeImportsDialog dialog = new OptimizeImportsDialog(project, message, FormatChangedTextUtil.hasChanges(dir));
|
||||
dialog.show();
|
||||
if (!dialog.isOK()) {
|
||||
return;
|
||||
}
|
||||
EditorSettingsExternalizable.getInstance().getOptions().SHOW_OPIMIZE_IMPORTS_DIALOG = !dialog.isDoNotAskMe();
|
||||
ReformatCodeAction.updateShowDialogSetting(dialog, "\"Optimize Imports\" dialog disabled");
|
||||
processDirectory = dialog.isProcessDirectory();
|
||||
includeSubdirectories = dialog.isIncludeSubdirectories();
|
||||
processDirectory = true;
|
||||
processOnlyVcsChangedFiles = dialog.isProcessOnlyVcsChangedFiles();
|
||||
}
|
||||
|
||||
if (processDirectory){
|
||||
new OptimizeImportsProcessor(project, dir, includeSubdirectories).run();
|
||||
new OptimizeImportsProcessor(project, dir, true, processOnlyVcsChangedFiles).run();
|
||||
}
|
||||
else{
|
||||
new OptimizeImportsProcessor(project, file).run();
|
||||
@@ -204,21 +199,43 @@ public class OptimizeImportsAction extends AnAction {
|
||||
return !LanguageImportStatements.INSTANCE.forFile(file).isEmpty();
|
||||
}
|
||||
|
||||
private static class OptimizeOnModuleDialog extends DialogWrapper {
|
||||
private final String myText;
|
||||
private static class OptimizeImportsDialog extends DialogWrapper {
|
||||
private final boolean myContextHasChanges;
|
||||
|
||||
OptimizeOnModuleDialog(Project project, String text) {
|
||||
private final String myText;
|
||||
private JCheckBox myOnlyVcsCheckBox;
|
||||
private final LastRunReformatCodeOptionsProvider myLastRunOptions;
|
||||
|
||||
OptimizeImportsDialog(Project project, String text, boolean hasChanges) {
|
||||
super(project, false);
|
||||
myText = text;
|
||||
myContextHasChanges = hasChanges;
|
||||
myLastRunOptions = new LastRunReformatCodeOptionsProvider(PropertiesComponent.getInstance());
|
||||
setOKButtonText(CodeInsightBundle.message("reformat.code.accept.button.text"));
|
||||
setTitle(CodeInsightBundle.message("process.optimize.imports"));
|
||||
init();
|
||||
}
|
||||
|
||||
public boolean isProcessOnlyVcsChangedFiles() {
|
||||
return myOnlyVcsCheckBox.isSelected();
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
protected JComponent createCenterPanel() {
|
||||
return new JLabel(myText);
|
||||
JPanel panel = new JPanel();
|
||||
BoxLayout layout = new BoxLayout(panel, BoxLayout.Y_AXIS);
|
||||
panel.setLayout(layout);
|
||||
|
||||
panel.add(new JLabel(myText));
|
||||
myOnlyVcsCheckBox = new JCheckBox(CodeInsightBundle.message("process.scope.changed.files"));
|
||||
boolean lastRunVcsChangedTextEnabled = myLastRunOptions.getLastTextRangeType() == TextRangeType.VCS_CHANGED_TEXT;
|
||||
|
||||
myOnlyVcsCheckBox.setEnabled(myContextHasChanges);
|
||||
myOnlyVcsCheckBox.setSelected(myContextHasChanges && lastRunVcsChangedTextEnabled);
|
||||
|
||||
panel.add(myOnlyVcsCheckBox);
|
||||
return panel;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+70
-2
@@ -25,16 +25,21 @@ import com.intellij.openapi.util.EmptyRunnable;
|
||||
import com.intellij.psi.PsiDirectory;
|
||||
import com.intellij.psi.PsiFile;
|
||||
import com.intellij.psi.impl.source.codeStyle.CodeStyleManagerImpl;
|
||||
import com.intellij.util.containers.ContainerUtil;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.FutureTask;
|
||||
|
||||
import static com.intellij.codeInsight.actions.OptimizeImportsProcessor.NotificationInfo.*;
|
||||
|
||||
public class OptimizeImportsProcessor extends AbstractLayoutCodeProcessor {
|
||||
private static final String PROGRESS_TEXT = CodeInsightBundle.message("progress.text.optimizing.imports");
|
||||
public static final String COMMAND_NAME = CodeInsightBundle.message("process.optimize.imports");
|
||||
private List<NotificationInfo> myOptimizerNotifications = ContainerUtil.newSmartList();
|
||||
|
||||
public OptimizeImportsProcessor(Project project) {
|
||||
super(project, COMMAND_NAME, PROGRESS_TEXT, false);
|
||||
@@ -48,6 +53,10 @@ public class OptimizeImportsProcessor extends AbstractLayoutCodeProcessor {
|
||||
super(project, directory, includeSubdirs, PROGRESS_TEXT, COMMAND_NAME, false);
|
||||
}
|
||||
|
||||
public OptimizeImportsProcessor(Project project, PsiDirectory directory, boolean includeSubdirs, boolean processOnlyVcsChangedFiles) {
|
||||
super(project, directory, includeSubdirs, PROGRESS_TEXT, COMMAND_NAME, processOnlyVcsChangedFiles);
|
||||
}
|
||||
|
||||
public OptimizeImportsProcessor(Project project, PsiFile file) {
|
||||
super(project, file, PROGRESS_TEXT, COMMAND_NAME, false);
|
||||
}
|
||||
@@ -77,20 +86,79 @@ public class OptimizeImportsProcessor extends AbstractLayoutCodeProcessor {
|
||||
}
|
||||
}
|
||||
}
|
||||
Runnable runnable = runnables.isEmpty() ? EmptyRunnable.getInstance() : new Runnable() {
|
||||
|
||||
Runnable runnable = !runnables.isEmpty() ? new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
CodeStyleManagerImpl.setSequentialProcessingAllowed(false);
|
||||
try {
|
||||
for (Runnable runnable : runnables) {
|
||||
runnable.run();
|
||||
retrieveAndStoreNotificationInfo(runnable);
|
||||
}
|
||||
putNotificationInfoIntoCollector();
|
||||
}
|
||||
finally {
|
||||
CodeStyleManagerImpl.setSequentialProcessingAllowed(true);
|
||||
}
|
||||
}
|
||||
};
|
||||
} : EmptyRunnable.getInstance();
|
||||
return new FutureTask<Boolean>(runnable, true);
|
||||
}
|
||||
|
||||
private void retrieveAndStoreNotificationInfo(@NotNull Runnable runnable) {
|
||||
if (runnable instanceof ImportOptimizer.CollectingInfoRunnable) {
|
||||
String optimizerMessage = ((ImportOptimizer.CollectingInfoRunnable)runnable).getUserNotificationInfo();
|
||||
myOptimizerNotifications.add(optimizerMessage != null ? new NotificationInfo(optimizerMessage) : NOTHING_CHANGED_NOTIFICATION);
|
||||
}
|
||||
else if (runnable == EmptyRunnable.getInstance()) {
|
||||
myOptimizerNotifications.add(NOTHING_CHANGED_NOTIFICATION);
|
||||
}
|
||||
else {
|
||||
myOptimizerNotifications.add(SOMETHING_CHANGED_WITHOUT_MESSAGE_NOTIFICATION);
|
||||
}
|
||||
}
|
||||
|
||||
private void putNotificationInfoIntoCollector() {
|
||||
LayoutCodeInfoCollector collector = getInfoCollector();
|
||||
if (collector == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
boolean atLeastOneOptimizerChangedSomething = false;
|
||||
for (NotificationInfo info : myOptimizerNotifications) {
|
||||
atLeastOneOptimizerChangedSomething |= info.isSomethingChanged();
|
||||
if (info.getMessage() != null) {
|
||||
collector.setOptimizeImportsNotification(info.getMessage());
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
collector.setOptimizeImportsNotification(atLeastOneOptimizerChangedSomething ? "imports optimized" : null);
|
||||
}
|
||||
|
||||
static class NotificationInfo {
|
||||
public static final NotificationInfo NOTHING_CHANGED_NOTIFICATION = new NotificationInfo(false, null);
|
||||
public static final NotificationInfo SOMETHING_CHANGED_WITHOUT_MESSAGE_NOTIFICATION = new NotificationInfo(true, null);
|
||||
|
||||
private final boolean mySomethingChanged;
|
||||
private final String myMessage;
|
||||
|
||||
NotificationInfo(@NotNull String message) {
|
||||
this(true, message);
|
||||
}
|
||||
|
||||
public boolean isSomethingChanged() {
|
||||
return mySomethingChanged;
|
||||
}
|
||||
|
||||
public String getMessage() {
|
||||
return myMessage;
|
||||
}
|
||||
|
||||
private NotificationInfo(boolean isSomethingChanged, @Nullable String message) {
|
||||
mySomethingChanged = isSomethingChanged;
|
||||
myMessage = message;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+4
-12
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2000-2012 JetBrains s.r.o.
|
||||
* Copyright 2000-2014 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.
|
||||
@@ -15,18 +15,10 @@
|
||||
*/
|
||||
package com.intellij.codeInsight.actions;
|
||||
|
||||
import org.jetbrains.annotations.NonNls;
|
||||
public interface OptionalReformatActions {
|
||||
|
||||
/**
|
||||
* @author Denis Zhdanov
|
||||
* @since 12/16/11 6:10 PM
|
||||
*/
|
||||
public class LayoutCodeConstants {
|
||||
boolean isOptimizeImports();
|
||||
|
||||
@NonNls public static final String OPTIMIZE_IMPORTS_KEY = "LayoutCode.optimizeImports";
|
||||
@NonNls public static final String REARRANGE_ENTRIES_KEY = "LayoutCode.rearrangeEntries";
|
||||
@NonNls public static final String PROCESS_CHANGED_TEXT_KEY = "LayoutCode.processChangedText";
|
||||
boolean isRearrangeCode();
|
||||
|
||||
private LayoutCodeConstants() {
|
||||
}
|
||||
}
|
||||
+53
-63
@@ -15,8 +15,10 @@
|
||||
*/
|
||||
package com.intellij.codeInsight.actions;
|
||||
|
||||
import com.intellij.codeInsight.CodeInsightBundle;
|
||||
import com.intellij.openapi.command.CommandProcessor;
|
||||
import com.intellij.openapi.components.ServiceManager;
|
||||
import com.intellij.openapi.diagnostic.Logger;
|
||||
import com.intellij.openapi.editor.Document;
|
||||
import com.intellij.openapi.editor.SelectionModel;
|
||||
import com.intellij.openapi.project.Project;
|
||||
@@ -25,21 +27,22 @@ import com.intellij.psi.PsiDocumentManager;
|
||||
import com.intellij.psi.PsiFile;
|
||||
import com.intellij.psi.codeStyle.arrangement.Rearranger;
|
||||
import com.intellij.psi.codeStyle.arrangement.engine.ArrangementEngine;
|
||||
import com.intellij.util.SmartList;
|
||||
import com.intellij.util.containers.ContainerUtil;
|
||||
import com.intellij.util.diff.FilesTooBigForDiffException;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.Callable;
|
||||
import java.util.concurrent.FutureTask;
|
||||
|
||||
public class RearrangeCodeProcessor extends AbstractLayoutCodeProcessor {
|
||||
|
||||
public static final String COMMAND_NAME = "Rearrange code";
|
||||
public static final String PROGRESS_TEXT = "Rearranging code...";
|
||||
public static final String PROGRESS_TEXT = CodeInsightBundle.message("process.rearrange.code");
|
||||
|
||||
@Nullable private SelectionModel mySelectionModel;
|
||||
private static final Logger LOG = Logger.getInstance(RearrangeCodeProcessor.class);
|
||||
private SelectionModel mySelectionModel;
|
||||
|
||||
public RearrangeCodeProcessor(@NotNull AbstractLayoutCodeProcessor previousProcessor) {
|
||||
super(previousProcessor, COMMAND_NAME, PROGRESS_TEXT);
|
||||
@@ -49,14 +52,16 @@ public class RearrangeCodeProcessor extends AbstractLayoutCodeProcessor {
|
||||
super(previousProcessor, COMMAND_NAME, PROGRESS_TEXT);
|
||||
mySelectionModel = selectionModel;
|
||||
}
|
||||
|
||||
public RearrangeCodeProcessor(@NotNull Project project,
|
||||
@NotNull PsiFile file,
|
||||
@Nullable SelectionModel selectionModel) {
|
||||
super(project, file, PROGRESS_TEXT, COMMAND_NAME, false);
|
||||
|
||||
public RearrangeCodeProcessor(@NotNull PsiFile file, @NotNull SelectionModel selectionModel) {
|
||||
super(file.getProject(), file, PROGRESS_TEXT, COMMAND_NAME, false);
|
||||
mySelectionModel = selectionModel;
|
||||
}
|
||||
|
||||
public RearrangeCodeProcessor(@NotNull PsiFile file) {
|
||||
super(file.getProject(), file, PROGRESS_TEXT, COMMAND_NAME, false);
|
||||
}
|
||||
|
||||
public RearrangeCodeProcessor(@NotNull Project project,
|
||||
@NotNull PsiFile[] files,
|
||||
@NotNull String commandName,
|
||||
@@ -70,70 +75,55 @@ public class RearrangeCodeProcessor extends AbstractLayoutCodeProcessor {
|
||||
return new FutureTask<Boolean>(new Callable<Boolean>() {
|
||||
@Override
|
||||
public Boolean call() throws Exception {
|
||||
Collection<TextRange> ranges = processChangedTextOnly ? FormatChangedTextUtil.getChangedTextRanges(myProject, file)
|
||||
: getRangesToFormat(file);
|
||||
try {
|
||||
Collection<TextRange> ranges = getRangesToFormat(file, processChangedTextOnly);
|
||||
Document document = PsiDocumentManager.getInstance(myProject).getDocument(file);
|
||||
|
||||
RearrangeCommand rearranger = new RearrangeCommand(myProject, file, COMMAND_NAME, ranges);
|
||||
if (rearranger.couldRearrange()) {
|
||||
rearranger.run();
|
||||
if (document != null && Rearranger.EXTENSION.forLanguage(file.getLanguage()) != null) {
|
||||
Runnable command = prepareRearrangeCommand(file, ranges);
|
||||
PsiDocumentManager.getInstance(myProject).doPostponedOperationsAndUnblockDocument(document);
|
||||
try {
|
||||
CommandProcessor.getInstance().executeCommand(myProject, command, COMMAND_NAME, null);
|
||||
}
|
||||
finally {
|
||||
PsiDocumentManager.getInstance(myProject).commitDocument(document);
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
catch (FilesTooBigForDiffException e) {
|
||||
handleFileTooBigException(LOG, e, file);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public Collection<TextRange> getRangesToFormat(@NotNull PsiFile file) {
|
||||
final List<TextRange> ranges = new SmartList<TextRange>();
|
||||
if (mySelectionModel != null && mySelectionModel.hasSelection()) {
|
||||
ranges.add(TextRange.create(mySelectionModel.getSelectionStart(), mySelectionModel.getSelectionEnd()));
|
||||
}
|
||||
else {
|
||||
ranges.add(TextRange.create(0, file.getTextLength()));
|
||||
}
|
||||
return ranges;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
class RearrangeCommand {
|
||||
@NotNull private PsiFile myFile;
|
||||
@NotNull private String myCommandName;
|
||||
@NotNull private Project myProject;
|
||||
private Document myDocument;
|
||||
private Runnable myCommand;
|
||||
private final Collection<TextRange> myRanges;
|
||||
|
||||
RearrangeCommand(@NotNull Project project, @NotNull PsiFile file, @NotNull String commandName, @NotNull Collection<TextRange> ranges) {
|
||||
myProject = project;
|
||||
myFile = file;
|
||||
myRanges = ranges;
|
||||
myCommandName = commandName;
|
||||
myDocument = PsiDocumentManager.getInstance(project).getDocument(file);
|
||||
}
|
||||
|
||||
boolean couldRearrange() {
|
||||
return myDocument != null && Rearranger.EXTENSION.forLanguage(myFile.getLanguage()) != null;
|
||||
}
|
||||
|
||||
void run() {
|
||||
assert myDocument != null;
|
||||
prepare();
|
||||
try {
|
||||
CommandProcessor.getInstance().executeCommand(myProject, myCommand, myCommandName, null);
|
||||
}
|
||||
finally {
|
||||
PsiDocumentManager.getInstance(myProject).commitDocument(myDocument);
|
||||
}
|
||||
}
|
||||
|
||||
private void prepare() {
|
||||
@NotNull
|
||||
private Runnable prepareRearrangeCommand(@NotNull final PsiFile file, @NotNull final Collection<TextRange> ranges) {
|
||||
final ArrangementEngine engine = ServiceManager.getService(myProject, ArrangementEngine.class);
|
||||
myCommand = new Runnable() {
|
||||
return new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
engine.arrange(myFile, myRanges);
|
||||
engine.arrange(file, ranges);
|
||||
if (getInfoCollector() != null) {
|
||||
String info = engine.getUserNotificationInfo();
|
||||
getInfoCollector().setRearrangeCodeNotification(info);
|
||||
}
|
||||
}
|
||||
};
|
||||
PsiDocumentManager.getInstance(myProject).doPostponedOperationsAndUnblockDocument(myDocument);
|
||||
}
|
||||
|
||||
public Collection<TextRange> getRangesToFormat(@NotNull PsiFile file, boolean processChangedTextOnly) throws FilesTooBigForDiffException {
|
||||
if (mySelectionModel != null) {
|
||||
return getSelectedRanges(mySelectionModel);
|
||||
}
|
||||
|
||||
if (processChangedTextOnly) {
|
||||
return FormatChangedTextUtil.getChangedTextRanges(myProject, file);
|
||||
}
|
||||
|
||||
return ContainerUtil.newSmartList(file.getTextRange());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,32 +16,22 @@
|
||||
|
||||
package com.intellij.codeInsight.actions;
|
||||
|
||||
import com.intellij.application.options.editor.EditorOptions;
|
||||
import com.intellij.codeInsight.CodeInsightBundle;
|
||||
import com.intellij.find.impl.FindInProjectUtil;
|
||||
import com.intellij.formatting.FormattingModelBuilder;
|
||||
import com.intellij.ide.util.PropertiesComponent;
|
||||
import com.intellij.lang.LanguageFormatting;
|
||||
import com.intellij.notification.Notification;
|
||||
import com.intellij.notification.NotificationListener;
|
||||
import com.intellij.notification.NotificationType;
|
||||
import com.intellij.notification.Notifications;
|
||||
import com.intellij.openapi.actionSystem.*;
|
||||
import com.intellij.openapi.application.ApplicationManager;
|
||||
import com.intellij.openapi.diagnostic.Logger;
|
||||
import com.intellij.openapi.editor.Editor;
|
||||
import com.intellij.openapi.editor.ex.EditorSettingsExternalizable;
|
||||
import com.intellij.openapi.module.Module;
|
||||
import com.intellij.openapi.options.ShowSettingsUtil;
|
||||
import com.intellij.openapi.project.DumbAware;
|
||||
import com.intellij.openapi.project.DumbService;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.util.TextRange;
|
||||
import com.intellij.openapi.vcs.changes.ChangeListManagerImpl;
|
||||
import com.intellij.openapi.vfs.ReadonlyStatusHandler;
|
||||
import com.intellij.openapi.vfs.VirtualFile;
|
||||
import com.intellij.openapi.wm.IdeFrame;
|
||||
import com.intellij.openapi.wm.ex.WindowManagerEx;
|
||||
import com.intellij.psi.*;
|
||||
import com.intellij.psi.search.GlobalSearchScope;
|
||||
import com.intellij.psi.search.LocalSearchScope;
|
||||
@@ -53,8 +43,6 @@ import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.annotations.TestOnly;
|
||||
|
||||
import javax.swing.*;
|
||||
import javax.swing.event.HyperlinkEvent;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.regex.Pattern;
|
||||
@@ -95,14 +83,14 @@ public class ReformatCodeAction extends AnAction implements DumbAware {
|
||||
if (selectedFlags == null)
|
||||
return;
|
||||
|
||||
final boolean processOnlyChangedText = selectedFlags.isProcessOnlyChangedText();
|
||||
final boolean processOnlyChangedText = selectedFlags.getTextRangeType() == TextRangeType.VCS_CHANGED_TEXT;
|
||||
final boolean shouldOptimizeImports = selectedFlags.isOptimizeImports() && !DumbService.getInstance(project).isDumb();
|
||||
|
||||
AbstractLayoutCodeProcessor processor = new ReformatCodeProcessor(project, convertToPsiFiles(files, project), null, processOnlyChangedText);
|
||||
if (shouldOptimizeImports) {
|
||||
processor = new OptimizeImportsProcessor(processor);
|
||||
}
|
||||
if (selectedFlags.isRearrangeEntries()) {
|
||||
if (selectedFlags.isRearrangeCode()) {
|
||||
processor = new RearrangeCodeProcessor(processor);
|
||||
}
|
||||
|
||||
@@ -134,15 +122,7 @@ public class ReformatCodeAction extends AnAction implements DumbAware {
|
||||
}
|
||||
}
|
||||
|
||||
boolean optimizeImports = ReformatFilesDialog.isOptmizeImportsOptionOn();
|
||||
boolean processWholeFile = false;
|
||||
boolean processChangedTextOnly = PropertiesComponent.getInstance().getBoolean(LayoutCodeConstants.PROCESS_CHANGED_TEXT_KEY, false);
|
||||
boolean rearrangeEntries = getLastSavedRearrangeCbState(project, file);
|
||||
|
||||
final boolean showDialog = EditorSettingsExternalizable.getInstance().getOptions().SHOW_REFORMAT_DIALOG;
|
||||
|
||||
if (file == null && dir == null) return;
|
||||
if (file == null) {
|
||||
if (file == null && dir != null) {
|
||||
DirectoryFormattingOptions options = getDirectoryFormattingOptions(project, dir);
|
||||
if (options != null) {
|
||||
reformatDirectory(project, dir, options);
|
||||
@@ -150,57 +130,29 @@ public class ReformatCodeAction extends AnAction implements DumbAware {
|
||||
return;
|
||||
}
|
||||
|
||||
if (showDialog) {
|
||||
LayoutCodeOptions selectedFlags = getLayoutCodeOptions(project, file, dir, hasSelection);
|
||||
if (selectedFlags == null)
|
||||
return;
|
||||
if (file == null || editor == null) return;
|
||||
|
||||
optimizeImports = selectedFlags.isOptimizeImports();
|
||||
rearrangeEntries = selectedFlags.isRearrangeEntries();
|
||||
processWholeFile = selectedFlags.isProcessWholeFile();
|
||||
processChangedTextOnly = selectedFlags.isProcessOnlyChangedText();
|
||||
LastRunReformatCodeOptionsProvider provider = new LastRunReformatCodeOptionsProvider(PropertiesComponent.getInstance());
|
||||
ReformatCodeRunOptions currentRunOptions = provider.getLastRunOptions(file);
|
||||
|
||||
if (selectedFlags.isProcessDirectory()) {
|
||||
assert dir != null : "File = " + file + ", Element = " + CommonDataKeys.PSI_ELEMENT.getData(dataContext);
|
||||
reformatDirectory(project, dir, selectedFlags);
|
||||
return;
|
||||
TextRangeType processingScope = currentRunOptions.getTextRangeType();
|
||||
if (hasSelection) {
|
||||
processingScope = TextRangeType.SELECTED_TEXT;
|
||||
}
|
||||
else if (processingScope == TextRangeType.VCS_CHANGED_TEXT) {
|
||||
if (isChangeNotTrackedForFile(project, file)) {
|
||||
processingScope = TextRangeType.WHOLE_FILE;
|
||||
}
|
||||
}
|
||||
|
||||
if (!showDialog && processChangedTextOnly && isChangeNotTrackedForFile(project, file)) {
|
||||
processChangedTextOnly = false;
|
||||
}
|
||||
|
||||
final TextRange range;
|
||||
final boolean processSelectedText = !processWholeFile && hasSelection;
|
||||
if (processSelectedText) {
|
||||
range = TextRange.create(editor.getSelectionModel().getSelectionStart(), editor.getSelectionModel().getSelectionEnd());
|
||||
}
|
||||
else{
|
||||
range = null;
|
||||
}
|
||||
|
||||
AbstractLayoutCodeProcessor processor;
|
||||
if (optimizeImports && range == null) {
|
||||
processor = new OptimizeImportsProcessor(project, file);
|
||||
processor = new ReformatCodeProcessor(processor, processChangedTextOnly);
|
||||
}
|
||||
else {
|
||||
processor = new ReformatCodeProcessor(project, file, range, !processSelectedText && processChangedTextOnly);
|
||||
processingScope = TextRangeType.WHOLE_FILE;
|
||||
}
|
||||
|
||||
if (rearrangeEntries) {
|
||||
if (processSelectedText && editor != null) {
|
||||
processor = new RearrangeCodeProcessor(processor, editor.getSelectionModel());
|
||||
}
|
||||
else {
|
||||
processor = new RearrangeCodeProcessor(processor);
|
||||
}
|
||||
}
|
||||
|
||||
processor.run();
|
||||
currentRunOptions.setProcessingScope(processingScope);
|
||||
new FileInEditorProcessor(file, editor, currentRunOptions).processCode();
|
||||
}
|
||||
|
||||
|
||||
private static boolean isChangeNotTrackedForFile(@NotNull Project project, @NotNull PsiFile file) {
|
||||
boolean isUnderVcs = VcsUtil.isFileUnderVcs(project, VcsUtil.getFilePath(file.getVirtualFile()));
|
||||
if (!isUnderVcs) return true;
|
||||
@@ -238,10 +190,7 @@ public class ReformatCodeAction extends AnAction implements DumbAware {
|
||||
@NotNull DirectoryFormattingOptions options)
|
||||
{
|
||||
AbstractLayoutCodeProcessor processor = new ReformatCodeProcessor(
|
||||
project,
|
||||
dir,
|
||||
options.isIncludeSubdirectories(),
|
||||
options.isProcessOnlyChangedText()
|
||||
project, dir, options.isIncludeSubdirectories(), options.getTextRangeType() == TextRangeType.VCS_CHANGED_TEXT
|
||||
);
|
||||
|
||||
registerScopeFilter(processor, options.getSearchScope());
|
||||
@@ -250,7 +199,7 @@ public class ReformatCodeAction extends AnAction implements DumbAware {
|
||||
if (options.isOptimizeImports()) {
|
||||
processor = new OptimizeImportsProcessor(processor);
|
||||
}
|
||||
if (options.isRearrangeEntries()) {
|
||||
if (options.isRearrangeCode()) {
|
||||
processor = new RearrangeCodeProcessor(processor);
|
||||
}
|
||||
|
||||
@@ -262,7 +211,7 @@ public class ReformatCodeAction extends AnAction implements DumbAware {
|
||||
@NotNull ReformatFilesOptions selectedFlags)
|
||||
{
|
||||
boolean shouldOptimizeImports = selectedFlags.isOptimizeImports() && !DumbService.getInstance(project).isDumb();
|
||||
boolean processOnlyChangedText = selectedFlags.isProcessOnlyChangedText();
|
||||
boolean processOnlyChangedText = selectedFlags.getTextRangeType() == TextRangeType.VCS_CHANGED_TEXT;
|
||||
|
||||
AbstractLayoutCodeProcessor processor;
|
||||
if (moduleContext != null)
|
||||
@@ -277,7 +226,7 @@ public class ReformatCodeAction extends AnAction implements DumbAware {
|
||||
processor = new OptimizeImportsProcessor(processor);
|
||||
}
|
||||
|
||||
if (selectedFlags.isRearrangeEntries()) {
|
||||
if (selectedFlags.isRearrangeCode()) {
|
||||
processor = new RearrangeCodeProcessor(processor);
|
||||
}
|
||||
|
||||
@@ -329,23 +278,6 @@ public class ReformatCodeAction extends AnAction implements DumbAware {
|
||||
}
|
||||
}
|
||||
|
||||
public static void updateShowDialogSetting(LayoutCodeDialog dialog, String title) {
|
||||
if (dialog.isDoNotAskMe()) {
|
||||
Notifications.Bus.notify(new Notification("Reformat Code", title,
|
||||
"<html>You can re-enable the dialog on the <a href=''>IDE Settings -> Editor</a> pane</html>",
|
||||
NotificationType.INFORMATION, new NotificationListener() {
|
||||
@Override
|
||||
public void hyperlinkUpdate(@NotNull Notification notification, @NotNull HyperlinkEvent e) {
|
||||
if (e.getEventType() == HyperlinkEvent.EventType.ACTIVATED) {
|
||||
final ShowSettingsUtil util = ShowSettingsUtil.getInstance();
|
||||
IdeFrame ideFrame = WindowManagerEx.getInstanceEx().findFrameFor(null);
|
||||
util.editConfigurable((JFrame)ideFrame, new EditorOptions());
|
||||
}
|
||||
}
|
||||
}));
|
||||
}
|
||||
}
|
||||
|
||||
public static PsiFile[] convertToPsiFiles(final VirtualFile[] files,Project project) {
|
||||
final PsiManager manager = PsiManager.getInstance(project);
|
||||
final ArrayList<PsiFile> result = new ArrayList<PsiFile>();
|
||||
@@ -457,31 +389,6 @@ public class ReformatCodeAction extends AnAction implements DumbAware {
|
||||
return dialog;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private static LayoutCodeOptions getLayoutCodeOptions(@NotNull Project project,
|
||||
@Nullable PsiFile file,
|
||||
@Nullable PsiDirectory dir,
|
||||
boolean hasSelection) {
|
||||
if (ApplicationManager.getApplication().isUnitTestMode()) {
|
||||
return (LayoutCodeOptions)myTestOptions;
|
||||
}
|
||||
LayoutCodeDialog dialog = new LayoutCodeDialog(project, CodeInsightBundle.message("process.reformat.code"),
|
||||
file, dir, hasSelection ? Boolean.TRUE : Boolean.FALSE, HELP_ID);
|
||||
if (!dialog.showAndGet()) {
|
||||
return null;
|
||||
}
|
||||
EditorSettingsExternalizable.getInstance().getOptions().SHOW_REFORMAT_DIALOG = !dialog.isDoNotAskMe();
|
||||
updateShowDialogSetting(dialog, "\"Reformat Code\" dialog disabled");
|
||||
return dialog;
|
||||
}
|
||||
|
||||
public static boolean getLastSavedRearrangeCbState(@NotNull Project project, @Nullable PsiFile file) {
|
||||
if (file != null) {
|
||||
return LayoutCodeSettingsStorage.getLastSavedRearrangeEntriesCbStateFor(project, file.getLanguage());
|
||||
}
|
||||
return LayoutCodeSettingsStorage.getLastSavedRearrangeEntriesCbStateFor(project);
|
||||
}
|
||||
|
||||
@TestOnly
|
||||
protected static void setTestOptions(ReformatFilesOptions options) {
|
||||
myTestOptions = options;
|
||||
|
||||
+48
-13
@@ -18,15 +18,14 @@ package com.intellij.codeInsight.actions;
|
||||
|
||||
import com.intellij.codeInsight.CodeInsightBundle;
|
||||
import com.intellij.formatting.FormattingProgressTask;
|
||||
import com.intellij.notification.Notification;
|
||||
import com.intellij.notification.NotificationType;
|
||||
import com.intellij.openapi.application.ApplicationBundle;
|
||||
import com.intellij.openapi.application.ApplicationManager;
|
||||
import com.intellij.openapi.diagnostic.Logger;
|
||||
import com.intellij.openapi.editor.Document;
|
||||
import com.intellij.openapi.editor.SelectionModel;
|
||||
import com.intellij.openapi.module.Module;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.util.TextRange;
|
||||
import com.intellij.psi.PsiDirectory;
|
||||
import com.intellij.psi.PsiDocumentManager;
|
||||
import com.intellij.psi.PsiFile;
|
||||
import com.intellij.psi.codeStyle.CodeStyleManager;
|
||||
import com.intellij.util.IncorrectOperationException;
|
||||
@@ -46,13 +45,24 @@ public class ReformatCodeProcessor extends AbstractLayoutCodeProcessor {
|
||||
|
||||
private static final Logger LOG = Logger.getInstance("#com.intellij.codeInsight.actions.ReformatCodeProcessor");
|
||||
|
||||
private final Collection<TextRange> myRanges = new ArrayList<TextRange>();
|
||||
private static final String PROGRESS_TEXT = CodeInsightBundle.message("reformat.progress.common.text");
|
||||
private final Collection<TextRange> myRanges = new ArrayList<TextRange>();
|
||||
private SelectionModel mySelectionModel;
|
||||
|
||||
public ReformatCodeProcessor(Project project, boolean processChangedTextOnly) {
|
||||
super(project, COMMAND_NAME, PROGRESS_TEXT, processChangedTextOnly);
|
||||
}
|
||||
|
||||
public ReformatCodeProcessor(@NotNull PsiFile file, @NotNull SelectionModel selectionModel) {
|
||||
super(file.getProject(), file, COMMAND_NAME, PROGRESS_TEXT, false);
|
||||
mySelectionModel = selectionModel;
|
||||
}
|
||||
|
||||
public ReformatCodeProcessor(AbstractLayoutCodeProcessor processor, @NotNull SelectionModel selectionModel) {
|
||||
super(processor, COMMAND_NAME, PROGRESS_TEXT);
|
||||
mySelectionModel = selectionModel;
|
||||
}
|
||||
|
||||
public ReformatCodeProcessor(AbstractLayoutCodeProcessor processor, boolean processChangedTextOnly) {
|
||||
super(processor, COMMAND_NAME, PROGRESS_TEXT);
|
||||
setProcessChangedTextOnly(processChangedTextOnly);
|
||||
@@ -73,6 +83,10 @@ public class ReformatCodeProcessor extends AbstractLayoutCodeProcessor {
|
||||
}
|
||||
}
|
||||
|
||||
public ReformatCodeProcessor(@NotNull PsiFile file, boolean processChangedTextOnly) {
|
||||
super(file.getProject(), file, PROGRESS_TEXT, COMMAND_NAME, processChangedTextOnly);
|
||||
}
|
||||
|
||||
public ReformatCodeProcessor(Project project, PsiFile[] files, @Nullable Runnable postRunnable, boolean processChangedTextOnly) {
|
||||
this(project, files, COMMAND_NAME, postRunnable, processChangedTextOnly);
|
||||
}
|
||||
@@ -92,23 +106,31 @@ public class ReformatCodeProcessor extends AbstractLayoutCodeProcessor {
|
||||
throws IncorrectOperationException
|
||||
{
|
||||
return new FutureTask<Boolean>(new Callable<Boolean>() {
|
||||
private Document myDocument;
|
||||
|
||||
@Override
|
||||
public Boolean call() throws Exception {
|
||||
FormattingProgressTask.FORMATTING_CANCELLED_FLAG.set(false);
|
||||
try {
|
||||
Collection<TextRange> ranges = getRangesToFormat(processChangedTextOnly, file);
|
||||
|
||||
CharSequence before = null;
|
||||
if (getInfoCollector() != null) {
|
||||
myDocument = PsiDocumentManager.getInstance(myProject).getDocument(file);
|
||||
LOG.assertTrue(myDocument != null);
|
||||
before = myDocument.getImmutableCharSequence();
|
||||
}
|
||||
|
||||
CodeStyleManager.getInstance(myProject).reformatText(file, ranges);
|
||||
|
||||
if (before != null) {
|
||||
prepareUserNotificationMessage(myDocument, before);
|
||||
}
|
||||
|
||||
return !FormattingProgressTask.FORMATTING_CANCELLED_FLAG.get();
|
||||
}
|
||||
catch (FilesTooBigForDiffException e) {
|
||||
LOG.info("Error while calculating changed ranges for: " + file.getVirtualFile(), e);
|
||||
if (!ApplicationManager.getApplication().isUnitTestMode()) {
|
||||
Notification notification = new Notification(ApplicationBundle.message("reformat.changed.text.file.too.big.notification.groupId"),
|
||||
ApplicationBundle.message("reformat.changed.text.file.too.big.notification.title"),
|
||||
ApplicationBundle.message("reformat.changed.text.file.too.big.notification.text", file.getName()),
|
||||
NotificationType.INFORMATION);
|
||||
notification.notify(file.getProject());
|
||||
}
|
||||
handleFileTooBigException(LOG, e, file);
|
||||
return false;
|
||||
}
|
||||
catch (IncorrectOperationException e) {
|
||||
@@ -122,8 +144,21 @@ public class ReformatCodeProcessor extends AbstractLayoutCodeProcessor {
|
||||
});
|
||||
}
|
||||
|
||||
private void prepareUserNotificationMessage(@NotNull Document document, @NotNull CharSequence before) {
|
||||
LOG.assertTrue(getInfoCollector() != null);
|
||||
int number = FormatChangedTextUtil.calculateChangedLinesNumber(document, before);
|
||||
if (number > 0) {
|
||||
String message = "formatted " + number + " line" + (number > 1 ? "s" : "");
|
||||
getInfoCollector().setReformatCodeNotification(message);
|
||||
}
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private Collection<TextRange> getRangesToFormat(boolean processChangedTextOnly, PsiFile file) throws FilesTooBigForDiffException {
|
||||
if (mySelectionModel != null) {
|
||||
return getSelectedRanges(mySelectionModel);
|
||||
}
|
||||
|
||||
if (processChangedTextOnly) {
|
||||
return FormatChangedTextUtil.getChangedTextRanges(myProject, file);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,58 @@
|
||||
/*
|
||||
* Copyright 2000-2014 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.codeInsight.actions;
|
||||
|
||||
public class ReformatCodeRunOptions implements LayoutCodeOptions {
|
||||
|
||||
private boolean myRearrangeCode;
|
||||
private boolean myOptimizeImports;
|
||||
private TextRangeType myProcessingScope;
|
||||
|
||||
public ReformatCodeRunOptions(TextRangeType processingScope) {
|
||||
myProcessingScope = processingScope;
|
||||
}
|
||||
|
||||
public void setProcessingScope(TextRangeType processingScope) {
|
||||
myProcessingScope = processingScope;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isOptimizeImports() {
|
||||
return myOptimizeImports;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isRearrangeCode() {
|
||||
return myRearrangeCode;
|
||||
}
|
||||
|
||||
public ReformatCodeRunOptions setRearrangeCode(boolean rearrangeCode) {
|
||||
myRearrangeCode = rearrangeCode;
|
||||
return this;
|
||||
}
|
||||
|
||||
public ReformatCodeRunOptions setOptimizeImports(boolean optimizeImports) {
|
||||
myOptimizeImports = optimizeImports;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public TextRangeType getTextRangeType() {
|
||||
return myProcessingScope;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -27,25 +27,27 @@ import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import javax.swing.*;
|
||||
|
||||
import static com.intellij.codeInsight.actions.TextRangeType.*;
|
||||
|
||||
public class ReformatFilesDialog extends DialogWrapper implements ReformatFilesOptions {
|
||||
@NotNull private Project myProject;
|
||||
private JPanel myPanel;
|
||||
private JCheckBox myOptimizeImports;
|
||||
private JCheckBox myOnlyChangedText;
|
||||
private JCheckBox myRearrangeEntriesCb;
|
||||
|
||||
private final LastRunReformatCodeOptionsProvider myLastRunSettings;
|
||||
|
||||
public ReformatFilesDialog(@NotNull Project project, @NotNull VirtualFile[] files) {
|
||||
super(project, true);
|
||||
myProject = project;
|
||||
setTitle(CodeInsightBundle.message("dialog.reformat.files.title"));
|
||||
myOptimizeImports.setSelected(isOptmizeImportsOptionOn());
|
||||
myLastRunSettings = new LastRunReformatCodeOptionsProvider(PropertiesComponent.getInstance());
|
||||
|
||||
boolean canTargetVcsChanges = FormatChangedTextUtil.hasChanges(files, project);
|
||||
myOnlyChangedText.setEnabled(canTargetVcsChanges);
|
||||
myOnlyChangedText.setSelected(
|
||||
canTargetVcsChanges && PropertiesComponent.getInstance().getBoolean(LayoutCodeConstants.PROCESS_CHANGED_TEXT_KEY, false)
|
||||
);
|
||||
myOptimizeImports.setSelected(isOptmizeImportsOptionOn());
|
||||
myRearrangeEntriesCb.setSelected(LayoutCodeSettingsStorage.getLastSavedRearrangeEntriesCbStateFor(myProject));
|
||||
myOnlyChangedText.setSelected(canTargetVcsChanges && myLastRunSettings.getLastTextRangeType() == VCS_CHANGED_TEXT);
|
||||
myOptimizeImports.setSelected(myLastRunSettings.getLastOptimizeImports());
|
||||
myRearrangeEntriesCb.setSelected(myLastRunSettings.getLastRearrangeCode());
|
||||
|
||||
setTitle(CodeInsightBundle.message("dialog.reformat.files.title"));
|
||||
init();
|
||||
}
|
||||
|
||||
@@ -60,25 +62,25 @@ public class ReformatFilesDialog extends DialogWrapper implements ReformatFilesO
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isProcessOnlyChangedText() {
|
||||
return myOnlyChangedText.isEnabled() && myOnlyChangedText.isSelected();
|
||||
public TextRangeType getTextRangeType() {
|
||||
return myOnlyChangedText.isEnabled() && myOnlyChangedText.isSelected()
|
||||
? VCS_CHANGED_TEXT
|
||||
: WHOLE_FILE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isRearrangeEntries() {
|
||||
public boolean isRearrangeCode() {
|
||||
return myRearrangeEntriesCb.isSelected();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void doOKAction() {
|
||||
super.doOKAction();
|
||||
PropertiesComponent.getInstance().setValue(LayoutCodeConstants.OPTIMIZE_IMPORTS_KEY, Boolean.toString(myOptimizeImports.isSelected()));
|
||||
PropertiesComponent.getInstance().setValue(LayoutCodeConstants.PROCESS_CHANGED_TEXT_KEY, Boolean.toString(myOnlyChangedText.isSelected()));
|
||||
LayoutCodeSettingsStorage.saveRearrangeEntriesOptionFor(myProject, isRearrangeEntries());
|
||||
}
|
||||
|
||||
static boolean isOptmizeImportsOptionOn() {
|
||||
return PropertiesComponent.getInstance().getBoolean(LayoutCodeConstants.OPTIMIZE_IMPORTS_KEY, false);
|
||||
myLastRunSettings.saveOptimizeImportsState(isOptimizeImports());
|
||||
myLastRunSettings.saveRearrangeCodeState(isRearrangeCode());
|
||||
if (myOnlyChangedText.isEnabled()) {
|
||||
myLastRunSettings.saveProcessVcsChangedTextState(getTextRangeType() == VCS_CHANGED_TEXT);
|
||||
}
|
||||
}
|
||||
|
||||
@Nullable
|
||||
|
||||
@@ -18,13 +18,7 @@ package com.intellij.codeInsight.actions;
|
||||
import com.intellij.psi.search.SearchScope;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
public interface ReformatFilesOptions {
|
||||
|
||||
boolean isOptimizeImports();
|
||||
|
||||
boolean isProcessOnlyChangedText();
|
||||
|
||||
boolean isRearrangeEntries();
|
||||
public interface ReformatFilesOptions extends LayoutCodeOptions {
|
||||
|
||||
@Nullable
|
||||
String getFileTypeMask();
|
||||
|
||||
@@ -0,0 +1,77 @@
|
||||
/*
|
||||
* Copyright 2000-2014 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.codeInsight.actions;
|
||||
|
||||
import com.intellij.lang.LanguageFormatting;
|
||||
import com.intellij.openapi.actionSystem.*;
|
||||
import com.intellij.openapi.editor.Editor;
|
||||
import com.intellij.openapi.project.DumbAware;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.psi.PsiDocumentManager;
|
||||
import com.intellij.psi.PsiFile;
|
||||
import org.jetbrains.annotations.NonNls;
|
||||
|
||||
public class ShowReformatFileDialog extends AnAction implements DumbAware {
|
||||
private static final @NonNls String HELP_ID = "editing.codeReformatting";
|
||||
|
||||
@Override
|
||||
public void update(AnActionEvent event) {
|
||||
Presentation presentation = event.getPresentation();
|
||||
DataContext dataContext = event.getDataContext();
|
||||
Project project = CommonDataKeys.PROJECT.getData(dataContext);
|
||||
Editor editor = CommonDataKeys.EDITOR.getData(dataContext);
|
||||
if (project == null || editor == null) {
|
||||
presentation.setEnabled(false);
|
||||
return;
|
||||
}
|
||||
|
||||
PsiFile file = PsiDocumentManager.getInstance(project).getPsiFile(editor.getDocument());
|
||||
if (file == null || file.getVirtualFile() == null) {
|
||||
presentation.setEnabled(false);
|
||||
return;
|
||||
}
|
||||
|
||||
if (LanguageFormatting.INSTANCE.forContext(file) != null) {
|
||||
presentation.setEnabled(true);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void actionPerformed(AnActionEvent event) {
|
||||
Presentation presentation = event.getPresentation();
|
||||
DataContext dataContext = event.getDataContext();
|
||||
Project project = CommonDataKeys.PROJECT.getData(dataContext);
|
||||
Editor editor = CommonDataKeys.EDITOR.getData(dataContext);
|
||||
if (project == null || editor == null) {
|
||||
presentation.setEnabled(false);
|
||||
return;
|
||||
}
|
||||
|
||||
PsiFile file = PsiDocumentManager.getInstance(project).getPsiFile(editor.getDocument());
|
||||
if (file == null || file.getVirtualFile() == null) {
|
||||
presentation.setEnabled(false);
|
||||
return;
|
||||
}
|
||||
|
||||
boolean hasSelection = editor.getSelectionModel().hasSelection();
|
||||
LayoutCodeDialog dialog = new LayoutCodeDialog(project, file, hasSelection, HELP_ID);
|
||||
dialog.show();
|
||||
|
||||
if (dialog.isOK()) {
|
||||
new FileInEditorProcessor(file, editor, dialog.getRunOptions()).processCode();
|
||||
}
|
||||
}
|
||||
}
|
||||
+30
-8
@@ -57,6 +57,15 @@ import static com.intellij.psi.codeStyle.arrangement.std.StdArrangementTokens.Se
|
||||
* @since 7/20/12 1:56 PM
|
||||
*/
|
||||
public class ArrangementEngine {
|
||||
private boolean myCodeChanged;
|
||||
|
||||
@Nullable
|
||||
public String getUserNotificationInfo() {
|
||||
if (myCodeChanged) {
|
||||
return "rearranged code";
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Arranges given PSI root contents that belong to the given ranges.
|
||||
@@ -87,8 +96,9 @@ public class ArrangementEngine {
|
||||
* @param file target PSI root
|
||||
* @param ranges target ranges to use within the given root
|
||||
*/
|
||||
@SuppressWarnings("MethodMayBeStatic")
|
||||
public void arrange(@NotNull PsiFile file, @NotNull Collection<TextRange> ranges, @Nullable final ArrangementCallback callback) {
|
||||
myCodeChanged = false;
|
||||
|
||||
final Document document = PsiDocumentManager.getInstance(file.getProject()).getDocument(file);
|
||||
if (document == null) {
|
||||
return;
|
||||
@@ -143,7 +153,7 @@ public class ArrangementEngine {
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private static <E extends ArrangementEntry> void doArrange(Context<E> context) {
|
||||
private <E extends ArrangementEntry> void doArrange(Context<E> context) {
|
||||
// The general idea is to process entries bottom-up where every processed group belongs to the same parent. We may not bother
|
||||
// with entries text ranges then. We use a list and a stack for achieving that than.
|
||||
//
|
||||
@@ -363,8 +373,8 @@ public class ArrangementEngine {
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private static <E extends ArrangementEntry> void doArrange(@NotNull List<ArrangementEntryWrapper<E>> wrappers,
|
||||
@NotNull Context<E> context) {
|
||||
private <E extends ArrangementEntry> void doArrange(@NotNull List<ArrangementEntryWrapper<E>> wrappers,
|
||||
@NotNull Context<E> context) {
|
||||
if (wrappers.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
@@ -408,7 +418,9 @@ public class ArrangementEngine {
|
||||
if (previous != null && previous.equals(previousInitial) || previous == null && previousInitial == null) {
|
||||
final int beforeOffset = arrangedWrapper.getStartOffset();
|
||||
final int afterOffset = arrangedWrapper.getEndOffset();
|
||||
context.changer.insertSection(context, arranged.get(i), newSectionsInfo, parentWrapper, beforeOffset, afterOffset);
|
||||
|
||||
boolean isInserted = context.changer.insertSection(context, arranged.get(i), newSectionsInfo, parentWrapper, beforeOffset, afterOffset);
|
||||
myCodeChanged = isInserted || myCodeChanged;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
@@ -416,6 +428,7 @@ public class ArrangementEngine {
|
||||
ArrangementEntryWrapper<E> next = i < arranged.size() - 1 ? map.get(arranged.get(i + 1)) : null;
|
||||
context.changer.replace(arrangedWrapper, initialWrapper, previous, next, context);
|
||||
context.changer.insertSection(context, arranged.get(i), newSectionsInfo, arrangedWrapper, initialWrapper, parentWrapper);
|
||||
myCodeChanged = true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -600,7 +613,7 @@ public class ArrangementEngine {
|
||||
@NotNull ArrangementEntryWrapper<E> initial,
|
||||
@Nullable ArrangementEntryWrapper<E> parent);
|
||||
|
||||
protected abstract void insertSection(@NotNull Context<E> context,
|
||||
protected abstract boolean insertSection(@NotNull Context<E> context,
|
||||
@NotNull E entry,
|
||||
@NotNull NewSectionInfo<E> newSectionsInfo,
|
||||
@Nullable ArrangementEntryWrapper<E> parent, int beforeOffset, int afterOffset);
|
||||
@@ -746,18 +759,22 @@ public class ArrangementEngine {
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void insertSection(@NotNull Context<E> context,
|
||||
protected boolean insertSection(@NotNull Context<E> context,
|
||||
@NotNull E entry,
|
||||
@NotNull NewSectionInfo<E> newSectionsInfo,
|
||||
ArrangementEntryWrapper<E> parent, int beforeOffset, int afterOffset) {
|
||||
boolean isInserted = false;
|
||||
final String afterComment = newSectionsInfo.getEndComment(entry);
|
||||
if (afterComment != null) {
|
||||
insert(context, afterOffset, "\n" + afterComment);
|
||||
isInserted = true;
|
||||
}
|
||||
final String beforeComment = newSectionsInfo.getStartComment(entry);
|
||||
if (beforeComment != null) {
|
||||
insert(context, beforeOffset, beforeComment + "\n");
|
||||
isInserted = true;
|
||||
}
|
||||
return isInserted;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -886,24 +903,29 @@ public class ArrangementEngine {
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void insertSection(@NotNull Context<E> context,
|
||||
protected boolean insertSection(@NotNull Context<E> context,
|
||||
@NotNull E entry,
|
||||
@NotNull NewSectionInfo<E> newSectionsInfo,
|
||||
@Nullable ArrangementEntryWrapper<E> parent,
|
||||
int beforeOffset, int afterOffset) {
|
||||
boolean isInserted = false;
|
||||
int diff = 0;
|
||||
final String afterComment = newSectionsInfo.getEndComment(entry);
|
||||
if (afterComment != null) {
|
||||
insert(context, afterOffset, "\n" + afterComment);
|
||||
diff += afterComment.length() + 1;
|
||||
isInserted = true;
|
||||
}
|
||||
final String beforeComment = newSectionsInfo.getStartComment(entry);
|
||||
if (beforeComment != null) {
|
||||
insert(context, beforeOffset, beforeComment + "\n");
|
||||
diff += beforeComment.length() + 1;
|
||||
isInserted = true;
|
||||
}
|
||||
|
||||
updateAllWrapperRanges(parent, diff);
|
||||
|
||||
return isInserted;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -548,6 +548,7 @@ action.OptimizeImports.text=Optimi_ze Imports...
|
||||
action.OptimizeImports.description=Remove unused imports and reorder/reorganize imports
|
||||
action.RearrangeCode.text=Rearrange Code
|
||||
action.RearrangeCode.description=Rearrange code
|
||||
action.ShowReformatFileDialog.text=Show Reformat File Dialog
|
||||
action.MoveStatementDown.text=Move Statement Do_wn
|
||||
action.MoveStatementDown.description=Move selected statements one line down
|
||||
action.MoveStatementUp.text=Move Statement _Up
|
||||
|
||||
@@ -7,6 +7,7 @@ reformat.directory.dialog.filters=Filters
|
||||
process.scope.directory=Directory ''{0}''
|
||||
process.scope.project=Project ''{0}''
|
||||
process.scope.module=Module ''{0}''
|
||||
process.scope.changed.files=only VCS changed files
|
||||
reformat.code.accept.button.text=Run
|
||||
process.scope.file=&File {0}
|
||||
reformat.option.selected.text=&Selected text
|
||||
@@ -25,6 +26,7 @@ progress.reformat.and.optimize.common.command.text=Reformat and Optimize Imports
|
||||
progress.reformat.stage.wrapping.blocks=Preparing...
|
||||
progress.reformat.stage.processing.blocks=Calculating changes...
|
||||
progress.reformat.stage.applying.changes=Storing changes...
|
||||
process.rearrange.code=Rearranging code...
|
||||
process.reformat.code=Reformat Code
|
||||
process.reformat.code.before.commit=Reformat Code Before Commit
|
||||
process.rearrange.code.before.commit=Rearrange Code Before Commit
|
||||
|
||||
@@ -87,6 +87,9 @@
|
||||
<action id="ReformatCode">
|
||||
<keyboard-shortcut first-keystroke="control alt L"/>
|
||||
</action>
|
||||
<action id="ShowReformatFileDialog">
|
||||
<keyboard-shortcut first-keystroke="control shift alt L"/>
|
||||
</action>
|
||||
<action id="Generate">
|
||||
<keyboard-shortcut first-keystroke="alt INSERT"/>
|
||||
</action>
|
||||
|
||||
@@ -938,5 +938,7 @@
|
||||
<reference ref="Arrangement.Rule.Group.Condition.Move.Down"/>
|
||||
</group>
|
||||
|
||||
<action id="ShowReformatFileDialog" class="com.intellij.codeInsight.actions.ShowReformatFileDialog"/>
|
||||
|
||||
</actions>
|
||||
</component>
|
||||
|
||||
@@ -0,0 +1,23 @@
|
||||
public class Add {
|
||||
|
||||
public void run() {
|
||||
int a = 1;
|
||||
a = 2;
|
||||
a = 3;
|
||||
a = 4;
|
||||
a = 5;
|
||||
a = 6;
|
||||
a = 7;
|
||||
a = 8;
|
||||
a = 9;
|
||||
a = 10;
|
||||
a = 11;
|
||||
a = 12;
|
||||
a = 13;
|
||||
a = 14;
|
||||
a = 15;
|
||||
a = 16;
|
||||
a = 17;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
public class Add {
|
||||
|
||||
public void run() {
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
public class ChangedAndDeleted {
|
||||
|
||||
public void run() {
|
||||
String a = "12";
|
||||
int f = 31;
|
||||
int g = 33;
|
||||
String b = "3";
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
public class ChangedAndDeleted {
|
||||
|
||||
public void run() {
|
||||
int a = 2;
|
||||
int b = 3;
|
||||
int c = 4;
|
||||
int d = 12;
|
||||
int e = 212;
|
||||
int f = 31;
|
||||
int g = 33;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
public class SingleLine {
|
||||
|
||||
public void run() {
|
||||
String a = "1";
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
public class SingleLine {
|
||||
|
||||
public void run() {
|
||||
int a = 2;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
public class DeletedLines {
|
||||
|
||||
public void run() {
|
||||
int a = 1;
|
||||
int e = 5;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
public class DeletedLines {
|
||||
|
||||
public void run() {
|
||||
int a = 1;
|
||||
int b = 2;
|
||||
int c = 3;
|
||||
int d = 4;
|
||||
int e = 5;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
public class Insert {
|
||||
|
||||
public void run() {
|
||||
int a = 1;
|
||||
int b = 3;
|
||||
int c = 4;
|
||||
String a = "aa";
|
||||
String b = "bb";
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
public class Insert {
|
||||
|
||||
public void run() {
|
||||
int a = 1;
|
||||
int b = 3;
|
||||
int c = 4;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
public class WhiteSpaces {
|
||||
|
||||
public void run() {
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
public class WhiteSpaces {
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
public void run() {
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
public class Modify {
|
||||
|
||||
public void run() {
|
||||
int a = 1;
|
||||
String ad = "s";
|
||||
int d = 6;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
public class Modify {
|
||||
|
||||
public void run() {
|
||||
int a = 1;
|
||||
int b = 3;
|
||||
int c = 4;
|
||||
int f = 5;
|
||||
int d = 6;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
public class Modified {
|
||||
|
||||
public void run() {
|
||||
String a = "1";
|
||||
String b = "2";
|
||||
String c = "3";
|
||||
String d = "4";
|
||||
String e = "5";
|
||||
String f = "6";
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
public class Modified {
|
||||
|
||||
public void run() {
|
||||
int a = 1;
|
||||
int b = 2;
|
||||
int c = 3;
|
||||
}
|
||||
}
|
||||
+91
@@ -0,0 +1,91 @@
|
||||
/*
|
||||
* Copyright 2000-2015 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.codeInsight.actions;
|
||||
|
||||
import com.intellij.openapi.editor.Document;
|
||||
import com.intellij.psi.PsiFile;
|
||||
import com.intellij.testFramework.PlatformTestCase;
|
||||
import com.intellij.testFramework.PlatformTestUtil;
|
||||
import com.intellij.testFramework.fixtures.LightPlatformCodeInsightFixtureTestCase;
|
||||
import org.junit.Assert;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
public class ChangedLinesCounterTest extends LightPlatformCodeInsightFixtureTestCase {
|
||||
|
||||
static {
|
||||
PlatformTestCase.initPlatformLangPrefix();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getTestDataPath() {
|
||||
return PlatformTestUtil.getCommunityPath().replace(File.separatorChar, '/')
|
||||
+ "/platform/platform-tests/testData/"
|
||||
+ "codeStyle/formatter/";
|
||||
}
|
||||
|
||||
@Override
|
||||
public void tearDown() throws Exception {
|
||||
myFixture.getFile().putUserData(FormatChangedTextUtil.TEST_REVISION_CONTENT, null);
|
||||
super.tearDown();
|
||||
}
|
||||
|
||||
public void doTest(int expectedLinesChanged) {
|
||||
myFixture.configureByFile(getTestName(true) + "_revision.java");
|
||||
PsiFile file = myFixture.getFile();
|
||||
CharSequence revisionContent = myFixture.getDocument(file).getCharsSequence();
|
||||
|
||||
myFixture.configureByFile(getTestName(true) + ".java");
|
||||
file = myFixture.getFile();
|
||||
Document document = myFixture.getDocument(file);
|
||||
|
||||
int linesChanged = FormatChangedTextUtil.calculateChangedLinesNumber(document, revisionContent);
|
||||
Assert.assertTrue(linesChanged > 0);
|
||||
Assert.assertEquals(expectedLinesChanged, linesChanged);
|
||||
}
|
||||
|
||||
public void testAddedLines() {
|
||||
doTest(17);
|
||||
}
|
||||
|
||||
public void testModifiedLines() {
|
||||
doTest(6);
|
||||
}
|
||||
|
||||
public void testDeletedLines() {
|
||||
doTest(3);
|
||||
}
|
||||
|
||||
public void testChangedSingleLine() {
|
||||
doTest(1);
|
||||
}
|
||||
|
||||
public void testChangedAndDeleted() {
|
||||
doTest(6);
|
||||
}
|
||||
|
||||
public void testModification() {
|
||||
doTest(3);
|
||||
}
|
||||
|
||||
public void testInsert() {
|
||||
doTest(2);
|
||||
}
|
||||
|
||||
public void testLotsWhiteSpaces() {
|
||||
doTest(19);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user