package com.jetbrains.lang.dart.ide.actions;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.application.ex.ApplicationManagerEx;
import com.intellij.openapi.command.CommandProcessor;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.editor.Document;
import com.intellij.openapi.editor.Editor;
import com.intellij.openapi.fileEditor.FileDocumentManager;
import com.intellij.openapi.progress.ProgressIndicator;
import com.intellij.openapi.progress.ProgressManager;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.ui.Messages;
import com.intellij.openapi.util.io.FileUtil;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.openapi.vfs.ReadonlyStatusHandler;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.psi.PsiFile;
import com.intellij.psi.codeStyle.CodeStyleSettingsManager;
import com.jetbrains.lang.dart.DartBundle;
import com.jetbrains.lang.dart.DartLanguage;
import com.jetbrains.lang.dart.analyzer.DartAnalysisServerService;
import gnu.trove.THashMap;
import org.dartlang.analysis.server.protocol.SourceEdit;
import org.jetbrains.annotations.NotNull;
import java.util.List;
import java.util.Map;
public class DartStyleAction extends AbstractDartFileProcessingAction {
private static final Logger LOG = Logger.getInstance(DartStyleAction.class.getName());
public DartStyleAction() {
super(DartBundle.message("dart.style.action.name"), DartBundle.message("dart.style.action.description"), null);
}
@NotNull
@Override
protected String getActionTextForEditor() {
return DartBundle.message("dart.style.action.name");
}
@NotNull
@Override
protected String getActionTextForFiles() {
return DartBundle.message("dart.style.action.name.ellipsis"); // because with dialog
}
protected void runOverEditor(@NotNull final Project project, @NotNull final Editor editor, @NotNull final PsiFile psiFile) {
final Document document = editor.getDocument();
if (!ReadonlyStatusHandler.ensureDocumentWritable(project, document)) return;
final int caretOffset = editor.getCaretModel().getOffset();
final int lineLength = getRightMargin(project);
final DartAnalysisServerService das = DartAnalysisServerService.getInstance(project);
das.updateFilesContent();
DartAnalysisServerService.FormatResult formatResult = das.edit_format(psiFile.getVirtualFile(), caretOffset, 0, lineLength);
if (formatResult == null) {
showHintLater(editor, DartBundle.message("dart.style.hint.failed"), true);
LOG.warn("Unexpected response from edit_format, formatResult is null");
return;
}
final Runnable runnable = () -> {
final List<SourceEdit> edits = formatResult.getEdits();
if (edits == null || edits.size() == 0) {
showHintLater(editor, DartBundle.message("dart.style.hint.already.good"), false);
}
else if (edits.size() == 1) {
final String replacement = StringUtil.convertLineSeparators(edits.get(0).getReplacement());
document.replaceString(0, document.getTextLength(), replacement);
final int offset = das.getConvertedOffset(psiFile.getVirtualFile(), formatResult.getOffset());
editor.getCaretModel().moveToOffset(offset);
showHintLater(editor, DartBundle.message("dart.style.hint.success"), false);
}
else {
showHintLater(editor, DartBundle.message("dart.style.hint.failed"), true);
LOG.warn("Unexpected response from edit_format, formatResult.getEdits().size() = " + edits.size());
}
};
ApplicationManager.getApplication().runWriteAction(
() -> CommandProcessor.getInstance().executeCommand(project, runnable, DartBundle.message("dart.style.action.name"), null));
}
protected void runOverFiles(@NotNull final Project project, @NotNull final List<VirtualFile> dartFiles) {
if (dartFiles.isEmpty()) {
Messages.showInfoMessage(project, DartBundle.message("dart.style.files.no.dart.files"), DartBundle.message("dart.style.action.name"));
return;
}
if (Messages.showOkCancelDialog(project, DartBundle.message("dart.style.files.dialog.question", dartFiles.size()),
DartBundle.message("dart.style.action.name"), null) != Messages.OK) {
return;
}
runDartfmt(project, dartFiles);
}
// keep public to be accessible in 3rd party plugins
public static void runDartfmt(@NotNull final Project project, @NotNull final List<VirtualFile> dartFiles) {
final Map<VirtualFile, String> fileToNewContentMap = new THashMap<>();
final int lineLength = getRightMargin(project);
final Runnable runnable = () -> {
double fraction = 0.0;
for (final VirtualFile virtualFile : dartFiles) {
fraction += 1.0;
final ProgressIndicator indicator = ProgressManager.getInstance().getProgressIndicator();
if (indicator != null) {
indicator.checkCanceled();
indicator.setFraction(fraction / dartFiles.size());
indicator.setText2(FileUtil.toSystemDependentName(virtualFile.getPath()));
}
final DartAnalysisServerService.FormatResult formatResult =
DartAnalysisServerService.getInstance(project).edit_format(virtualFile, 0, 0, lineLength);
if (formatResult != null && formatResult.getEdits() != null && formatResult.getEdits().size() == 1) {
final String replacement = StringUtil.convertLineSeparators(formatResult.getEdits().get(0).getReplacement());
fileToNewContentMap.put(virtualFile, replacement);
}
}
};
DartAnalysisServerService.getInstance(project).updateFilesContent();
final boolean ok = ApplicationManagerEx.getApplicationEx()
.runProcessWithProgressSynchronously(runnable, DartBundle.message("dart.style.action.name"), true, project);
if (ok) {
final Runnable onSuccessRunnable = () -> {
CommandProcessor.getInstance().markCurrentCommandAsGlobal(project);
for (Map.Entry<VirtualFile, String> entry : fileToNewContentMap.entrySet()) {
final VirtualFile file = entry.getKey();
final Document document = FileDocumentManager.getInstance().getDocument(file);
final String newContent = entry.getValue();
if (document != null && newContent != null) {
document.setText(newContent);
}
}
};
ApplicationManager.getApplication().runWriteAction(() -> CommandProcessor.getInstance()
.executeCommand(project, onSuccessRunnable, DartBundle.message("dart.style.action.name"), null));
}
}
private static int getRightMargin(@NotNull Project project) {
return CodeStyleSettingsManager.getSettings(project).getCommonSettings(DartLanguage.INSTANCE).RIGHT_MARGIN;
}
}