encoding review followup

This commit is contained in:
Alexey Kudravtsev
2013-02-28 15:01:40 +04:00
parent 63de67fb6d
commit ca0377afef
7 changed files with 36 additions and 50 deletions
@@ -94,12 +94,12 @@ public class CharsetToolkit {
public static final byte[] UTF32LE_BOM = {-1, -2, 0, 0 };
@NonNls public static final String FILE_ENCODING_PROPERTY = "file.encoding";
@NonNls private static final Map<Charset, byte[]> CHARSET_TO_BOM = new THashMap<Charset, byte[]>(2);
@NonNls private static final Map<Charset, byte[]> CHARSET_TO_MANDATORY_BOM = new THashMap<Charset, byte[]>(2);
static {
CHARSET_TO_BOM.put(UTF_16LE_CHARSET, UTF16LE_BOM);
CHARSET_TO_BOM.put(UTF_16BE_CHARSET, UTF16BE_BOM);
CHARSET_TO_BOM.put(UTF_32BE_CHARSET, UTF32BE_BOM);
CHARSET_TO_BOM.put(UTF_32LE_CHARSET, UTF32LE_BOM);
CHARSET_TO_MANDATORY_BOM.put(UTF_16LE_CHARSET, UTF16LE_BOM);
CHARSET_TO_MANDATORY_BOM.put(UTF_16BE_CHARSET, UTF16BE_BOM);
CHARSET_TO_MANDATORY_BOM.put(UTF_32BE_CHARSET, UTF32BE_BOM);
CHARSET_TO_MANDATORY_BOM.put(UTF_32LE_CHARSET, UTF32LE_BOM);
}
/**
@@ -503,12 +503,13 @@ public class CharsetToolkit {
@Nullable
public static byte[] getBom(@NotNull Charset charset) {
return CHARSET_TO_BOM.get(charset);
return CHARSET_TO_MANDATORY_BOM.get(charset);
}
// byte sequence for this encoding is allowed to be prepended with this BOM
public static boolean canHaveBom(@NotNull Charset charset, @NotNull byte[] bom) {
return charset.equals(UTF8_CHARSET) && Arrays.equals(bom, UTF8_BOM) || Arrays.equals(getBom(charset), bom);
return charset.equals(UTF8_CHARSET) && Arrays.equals(bom, UTF8_BOM)
|| Arrays.equals(getBom(charset), bom);
}
@Nullable
@@ -138,6 +138,9 @@ public class LossyEncodingInspection extends LocalInspectionTool {
@NotNull String text,
@NotNull Charset charset,
@NotNull Project project) {
FileDocumentManager documentManager = FileDocumentManager.getInstance();
Document document = documentManager.getDocument(virtualFile);
if (document == null) return true;
byte[] bytes;
try {
bytes = virtualFile.contentsToByteArray();
@@ -145,9 +148,6 @@ public class LossyEncodingInspection extends LocalInspectionTool {
catch (IOException e) {
return true;
}
FileDocumentManager documentManager = FileDocumentManager.getInstance();
Document document = documentManager.getDocument(virtualFile);
if (document == null) return true;
String separator = LoadTextUtil.detectLineSeparator(virtualFile, false);
if (separator == null) {
separator = documentManager.isDocumentUnsaved(document) ?
@@ -62,10 +62,7 @@ public class ChangeFileEncodingAction extends AnAction implements DumbAware {
Document document = documentManager.getDocument(virtualFile);
if (document == null) return false;
boolean canConvert = EncodingUtil.checkCanConvert(virtualFile) == null;
boolean canReload = EncodingUtil.checkCanReload(virtualFile).second == null;
return canConvert || canReload;
return EncodingUtil.checkCanConvert(virtualFile) == null || EncodingUtil.checkCanReload(virtualFile).second == null;
}
@Override
@@ -94,7 +91,7 @@ public class ChangeFileEncodingAction extends AnAction implements DumbAware {
Editor editor = PlatformDataKeys.EDITOR.getData(dataContext);
FileDocumentManager documentManager = FileDocumentManager.getInstance();
final Document document = documentManager.getDocument(virtualFile);
if (!allowDirectories && !virtualFile.isDirectory() && document == null) return null;
if (!allowDirectories && virtualFile.isDirectory() || document == null && !virtualFile.isDirectory()) return null;
final byte[] bytes;
try {
@@ -127,9 +124,13 @@ public class ChangeFileEncodingAction extends AnAction implements DumbAware {
return createCharsetsActionGroup(clearItemText, null, new Function<Charset, String>() {
@Override
public String fun(Charset charset) {
assert text != null : charset;
EncodingUtil.Magic8 safeToReload = myFile.isDirectory() ? EncodingUtil.Magic8.ABSOLUTELY : EncodingUtil.isSafeToReloadIn(myFile, text, bytes, charset);
EncodingUtil.Magic8 safeToConvert = myFile.isDirectory() ? EncodingUtil.Magic8.ABSOLUTELY : EncodingUtil.isSafeToConvertTo(myFile, text, bytes, charset);
boolean enabled = safeToReload != EncodingUtil.Magic8.NO_WAY || safeToConvert != EncodingUtil.Magic8.NO_WAY;
boolean enabled = safeToReload != EncodingUtil.Magic8.NO_WAY;
if (!enabled) {
EncodingUtil.Magic8 safeToConvert = myFile.isDirectory() ? EncodingUtil.Magic8.ABSOLUTELY : EncodingUtil.isSafeToConvertTo(myFile, text, bytes, charset);
enabled = safeToConvert != EncodingUtil.Magic8.NO_WAY;
}
return enabled ? "Change encoding to '"+charset.displayName()+"'" : null;
}
}); // no 'clear'
@@ -163,7 +164,6 @@ public class ChangeFileEncodingAction extends AnAction implements DumbAware {
if (isSafeToConvert == EncodingUtil.Magic8.ABSOLUTELY && isSafeToReload == EncodingUtil.Magic8.ABSOLUTELY) {
//change and forget
EncodingManager.getInstance().setEncoding(virtualFile, charset);
undo = new Runnable() {
@Override
public void run() {
@@ -178,7 +178,7 @@ public class ChangeFileEncodingAction extends AnAction implements DumbAware {
};
}
else {
IncompatibleEncodingDialog dialog = new IncompatibleEncodingDialog(document, virtualFile, bytes, charset, isSafeToReload, isSafeToConvert);
IncompatibleEncodingDialog dialog = new IncompatibleEncodingDialog(virtualFile, charset, isSafeToReload, isSafeToConvert);
dialog.show();
if (dialog.getExitCode() == IncompatibleEncodingDialog.RELOAD_EXIT_CODE) {
undo = new Runnable() {
@@ -48,6 +48,7 @@ import com.intellij.util.Processor;
import com.intellij.util.containers.ContainerUtil;
import com.intellij.util.containers.HashMap;
import com.intellij.util.ui.UIUtil;
import gnu.trove.THashSet;
import org.jdom.Element;
import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.NotNull;
@@ -315,15 +316,17 @@ public class EncodingProjectManagerImpl extends EncodingProjectManager {
if (!changed.isEmpty()) {
final Processor<VirtualFile> reloadProcessor = createChangeCharsetProcessor();
startReloadWithProgress(new Runnable() {
tryStartReloadWithProgress(new Runnable() {
@Override
public void run() {
Set<VirtualFile> processed = new THashSet<VirtualFile>();
next:
for (VirtualFile changedFile : changed) {
final Charset newCharset = newMap.get(changedFile);
Charset oldCharset = oldMap.get(changedFile);
if (!Comparing.equal(newCharset, oldCharset)) {
processSubFiles(changedFile, reloadProcessor);
for (VirtualFile processedFile : processed) {
if (VfsUtilCore.isAncestor(processedFile, changedFile, false)) continue next;
}
processSubFiles(changedFile, reloadProcessor);
processed.add(changedFile);
}
}
});
@@ -400,9 +403,9 @@ public class EncodingProjectManagerImpl extends EncodingProjectManager {
}
}
private boolean startReloadWithProgress(@NotNull final Runnable reloadAction) {
private boolean tryStartReloadWithProgress(@NotNull final Runnable reloadAction) {
Boolean suppress = SUPPRESS_RELOAD.get();
if (suppress != null && suppress) return false;
if (suppress == Boolean.TRUE) return false;
FileDocumentManager.getInstance().saveAllDocuments(); // consider all files as unmodified
return ProgressManager.getInstance().runProcessWithProgressSynchronously(new Runnable() {
@Override
@@ -413,7 +416,7 @@ public class EncodingProjectManagerImpl extends EncodingProjectManager {
}
private void reloadAllFilesUnder(final VirtualFile root) {
startReloadWithProgress(new Runnable() {
tryStartReloadWithProgress(new Runnable() {
@Override
public void run() {
processSubFiles(root, new Processor<VirtualFile>() {
@@ -430,7 +433,8 @@ public class EncodingProjectManagerImpl extends EncodingProjectManager {
}
});
}
else if (file.isCharsetSet()) {
// for not loaded files deep under project, reset encoding to give them chance re-detect the right one later
else if (file.isCharsetSet() && !file.equals(root)) {
file.setCharset(null);
}
return true;
@@ -103,18 +103,6 @@ public class EncodingUtil {
}
}
static boolean isSafeToChangeSilentlyTo(@NotNull VirtualFile virtualFile, @NotNull String text, @NotNull byte[] bytes, @NotNull Charset charset) {
String loaded = LoadTextUtil.getTextByBinaryPresentation(bytes, charset).toString();
boolean canReloadSilently = loaded.equals(text);
Pair<Charset, byte[]> chosen = LoadTextUtil.chooseMostlyHarmlessCharset(virtualFile.getCharset(), charset, text);
byte[] saved = chosen.second;
boolean canSaveSilently = Arrays.equals(saved, bytes);
return canReloadSilently && canSaveSilently;
}
public static void saveIn(@NotNull final Document document, final Editor editor, @NotNull final VirtualFile virtualFile, @NotNull final Charset charset) {
FileDocumentManager documentManager = FileDocumentManager.getInstance();
documentManager.saveDocument(document);
@@ -125,6 +113,7 @@ public class EncodingUtil {
return;
}
// first, save the file in the new charset and then mark the file as having the correct encoding
virtualFile.setCharset(charset);
try {
LoadTextUtil.write(project, virtualFile, virtualFile, document.getText(), document.getModificationStamp());
@@ -16,7 +16,6 @@
package com.intellij.openapi.vfs.encoding;
import com.intellij.icons.AllIcons;
import com.intellij.openapi.editor.Document;
import com.intellij.openapi.ui.DialogWrapper;
import com.intellij.openapi.ui.Messages;
import com.intellij.openapi.util.Pair;
@@ -30,24 +29,17 @@ import java.awt.event.ActionEvent;
import java.nio.charset.Charset;
public class IncompatibleEncodingDialog extends DialogWrapper {
@NotNull private final Document document;
@NotNull private final VirtualFile virtualFile;
@NotNull private final byte[] bytes;
@NotNull private final Charset charset;
@NotNull private final EncodingUtil.Magic8 safeToReload;
@NotNull private final EncodingUtil.Magic8 safeToConvert;
public IncompatibleEncodingDialog(@NotNull Document document,
@NotNull VirtualFile virtualFile,
@NotNull byte[] bytes,
public IncompatibleEncodingDialog(@NotNull VirtualFile virtualFile,
@NotNull final Charset charset,
@NotNull EncodingUtil.Magic8 safeToReload,
@NotNull EncodingUtil.Magic8 safeToConvert) {
super(false);
this.document = document;
this.virtualFile = virtualFile;
this.bytes = bytes;
this.charset = charset;
this.safeToReload = safeToReload;
this.safeToConvert = safeToConvert;
@@ -217,7 +217,7 @@ public class EncodingPanel extends EditorBasedWidget implements StatusBarWidget.
String toolTip = "File Encoding" +
(currentCharset == null ? "" : ": "+currentCharset.displayName()) +
(failReason == null ? "" : actionEnabled ? " ("+failReason+")" : " (change disabled: " + failReason + ")");
(actionEnabled ? "" : " (change disabled: " + failReason + ")");
myComponent.setToolTipText(toolTip);
myComponent.setText(text);