[ui] makes "Reveal/Show In" action independent from the arcane "File/Directory Path" one

GitOrigin-RevId: 7c15beab9bda3b3c1e6e821187fd344bc85ebc8d
This commit is contained in:
Roman Shevchenko
2019-07-23 17:44:15 +03:00
committed by intellij-monorepo-bot
parent fde43df81d
commit a1919a60ba
18 changed files with 349 additions and 355 deletions
@@ -7,7 +7,7 @@ import com.intellij.configurationStore.schemeManager.ROOT_CONFIG
import com.intellij.configurationStore.schemeManager.SchemeManagerFactoryBase
import com.intellij.ide.IdeBundle
import com.intellij.ide.actions.ImportSettingsFilenameFilter
import com.intellij.ide.actions.ShowFilePathAction
import com.intellij.ide.actions.RevealFileAction
import com.intellij.ide.plugins.IdeaPluginDescriptor
import com.intellij.ide.plugins.PluginManager
import com.intellij.ide.plugins.PluginManagerCore
@@ -86,8 +86,8 @@ open class ExportSettingsAction : AnAction(), DumbAware {
}
exportSettings(saveFile, markedComponents)
ShowFilePathAction.showDialog(getEventProject(e), IdeBundle.message("message.settings.exported.successfully"),
IdeBundle.message("title.export.successful"), saveFile.toFile(), null)
RevealFileAction.showDialog(getEventProject(e), IdeBundle.message("message.settings.exported.successfully"),
IdeBundle.message("title.export.successful"), saveFile.toFile(), null)
}
catch (e: IOException) {
Messages.showErrorDialog(IdeBundle.message("error.writing.settings", e.toString()), IdeBundle.message("title.error.writing.file"))
@@ -1,25 +1,10 @@
/*
* Copyright 2000-2016 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.
*/
// Copyright 2000-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
package com.intellij.ide.impl;
import com.intellij.ide.SelectInContext;
import com.intellij.ide.SelectInTarget;
import com.intellij.ide.StandardTargetWeights;
import com.intellij.ide.actions.RevealFileAction;
import com.intellij.ide.actions.ShowFilePathAction;
import com.intellij.openapi.project.DumbAware;
import com.intellij.openapi.vfs.VirtualFile;
@@ -31,15 +16,15 @@ import java.io.File;
public class ProjectViewSelectInExplorerTarget implements DumbAware, SelectInTarget {
@Override
public boolean canSelect(SelectInContext context) {
VirtualFile file = ShowFilePathAction.findLocalFile(context.getVirtualFile());
VirtualFile file = RevealFileAction.findLocalFile(context.getVirtualFile());
return file != null;
}
@Override
public void selectIn(SelectInContext context, boolean requestFocus) {
VirtualFile file = ShowFilePathAction.findLocalFile(context.getVirtualFile());
VirtualFile file = RevealFileAction.findLocalFile(context.getVirtualFile());
if (file != null) {
ShowFilePathAction.openFile(new File(file.getPresentableUrl()));
RevealFileAction.openFile(new File(file.getPresentableUrl()));
}
}
@@ -1,7 +1,7 @@
// Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
// Copyright 2000-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
package com.intellij.ide.util;
import com.intellij.ide.actions.ShowFilePathAction;
import com.intellij.ide.actions.RevealFileAction;
import com.intellij.ide.impl.ProjectViewSelectInTarget;
import com.intellij.ide.projectView.impl.ProjectViewPane;
import com.intellij.openapi.fileEditor.OpenFileDescriptor;
@@ -43,6 +43,6 @@ public class PsiNavigationSupportImpl extends PsiNavigationSupport {
@Override
public void openDirectoryInSystemFileManager(@NotNull File file) {
ShowFilePathAction.openDirectory(file);
RevealFileAction.openDirectory(file);
}
}
@@ -1,25 +1,11 @@
/*
* Copyright 2000-2012 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.
*/
// Copyright 2000-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
package com.intellij.history.core;
import com.intellij.history.core.changes.ChangeSet;
import com.intellij.history.utils.LocalHistoryLog;
import com.intellij.ide.BrowserUtil;
import com.intellij.ide.actions.ShowFilePathAction;
import com.intellij.ide.actions.RevealFileAction;
import com.intellij.notification.Notification;
import com.intellij.notification.NotificationType;
import com.intellij.notification.Notifications;
@@ -146,7 +132,7 @@ public class ChangeListStorageImpl implements ChangeListStorage {
}
else {
File file = new File(logFile);
ShowFilePathAction.openFile(file);
RevealFileAction.openFile(file);
}
}
}), null);
@@ -18,7 +18,7 @@ import com.intellij.history.integration.ui.models.RevisionProcessingProgress;
import com.intellij.history.utils.LocalHistoryLog;
import com.intellij.icons.AllIcons;
import com.intellij.ide.actions.ContextHelpAction;
import com.intellij.ide.actions.ShowFilePathAction;
import com.intellij.ide.actions.RevealFileAction;
import com.intellij.ide.ui.SplitterProportionsDataImpl;
import com.intellij.openapi.actionSystem.*;
import com.intellij.openapi.application.ApplicationManager;
@@ -436,7 +436,7 @@ public abstract class HistoryDialog<T extends HistoryDialogModel> extends FrameW
myModel.createPatch(p.getFileName(), p.getBaseDirName(), p.isReversePatch(), p.getEncoding());
showNotification(LocalHistoryBundle.message("message.patch.created"));
ShowFilePathAction.openFile(new File(p.getFileName()));
RevealFileAction.openFile(new File(p.getFileName()));
}
catch (VcsException | IOException e) {
showError(message("message.error.during.create.patch", e));
@@ -1,4 +1,4 @@
// Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
// Copyright 2000-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
package com.intellij.ide.actions;
import com.intellij.ide.troubleshooting.CompositeGeneralTroubleInfoCollector;
@@ -44,7 +44,7 @@ public class CollectZippedLogsAction extends AnAction implements DumbAware {
if (!doNotShowDialog) {
Messages.showIdeaMessageDialog(
project, "Included logs and settings may contain sensitive data.", "Sensitive Data",
new String[]{"Show in " + ShowFilePathAction.getFileManagerName()}, 1, Messages.getWarningIcon(),
new String[]{"Show in " + RevealFileAction.getFileManagerName()}, 1, Messages.getWarningIcon(),
new DialogWrapper.DoNotAskOption.Adapter() {
@Override
public void rememberChoice(final boolean selected, final int exitCode) {
@@ -62,8 +62,8 @@ public class CollectZippedLogsAction extends AnAction implements DumbAware {
return createZip(troubleshooting);
}
});
if (ShowFilePathAction.isSupported()) {
ShowFilePathAction.openFile(zippedLogsFile);
if (RevealFileAction.isSupported()) {
RevealFileAction.openFile(zippedLogsFile);
}
else {
Messages.showInfoMessage(zippedLogsFile.getAbsolutePath(), "Log File");
@@ -134,6 +134,6 @@ public class CollectZippedLogsAction extends AnAction implements DumbAware {
@NotNull
private static String getActionName() {
return "Compress Logs and Show in " + ShowFilePathAction.getFileManagerName();
return "Compress Logs and Show in " + RevealFileAction.getFileManagerName();
}
}
@@ -34,7 +34,7 @@ public class DumpThreadsAction extends AnAction implements DumbAware {
if (file != null) {
String url = FileUtil.getUrl(file);
String message = CommonBundle.message("thread.dump.is.taken", url);
return GROUP.createNotification("", message, NotificationType.INFORMATION, ShowFilePathAction.FILE_SELECTING_LISTENER);
return GROUP.createNotification("", message, NotificationType.INFORMATION, RevealFileAction.FILE_SELECTING_LISTENER);
}
else {
return GROUP.createNotification(CommonBundle.message("failed.to.take.thread.dump"), NotificationType.INFORMATION);
@@ -1,17 +1,70 @@
// Copyright 2000-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
package com.intellij.ide.actions;
import com.intellij.execution.configurations.GeneralCommandLine;
import com.intellij.execution.process.CapturingProcessHandler;
import com.intellij.execution.util.ExecUtil;
import com.intellij.ide.IdeBundle;
import com.intellij.idea.ActionsBundle;
import com.intellij.jna.JnaLoader;
import com.intellij.notification.Notification;
import com.intellij.notification.NotificationListener;
import com.intellij.openapi.actionSystem.AnActionEvent;
import com.intellij.openapi.actionSystem.CommonDataKeys;
import com.intellij.openapi.actionSystem.Presentation;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.project.DumbAwareAction;
import com.intellij.openapi.util.SystemInfo;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.ui.DialogWrapper;
import com.intellij.openapi.ui.Messages;
import com.intellij.openapi.util.*;
import com.intellij.openapi.util.io.FileUtil;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.openapi.vfs.VirtualFileSystem;
import com.intellij.openapi.vfs.newvfs.ArchiveFileSystem;
import com.intellij.util.SystemProperties;
import com.sun.jna.Native;
import com.sun.jna.platform.win32.Kernel32;
import com.sun.jna.platform.win32.WinDef;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.io.File;
import javax.swing.event.HyperlinkEvent;
import java.awt.*;
import java.io.*;
import java.net.URISyntaxException;
import java.net.URL;
import java.nio.charset.StandardCharsets;
import java.util.Arrays;
import java.util.Optional;
import java.util.stream.Stream;
import static com.intellij.openapi.util.text.StringUtil.defaultIfEmpty;
/**
* This helpful action opens a file or directory in a system file manager.
*
* @see ShowFilePathAction
*/
public class RevealFileAction extends DumbAwareAction {
private static final Logger LOG = Logger.getInstance(RevealFileAction.class);
public static final NotificationListener FILE_SELECTING_LISTENER = new NotificationListener.Adapter() {
@Override
protected void hyperlinkActivated(@NotNull Notification notification, @NotNull HyperlinkEvent e) {
URL url = e.getURL();
if (url != null) {
try {
openFile(new File(url.toURI()));
}
catch (URISyntaxException ex) {
LOG.warn("invalid URL: " + url, ex);
}
}
notification.expire();
}
};
public RevealFileAction() {
getTemplatePresentation().setText(getActionName());
@@ -19,22 +72,210 @@ public class RevealFileAction extends DumbAwareAction {
@Override
public void update(@NotNull AnActionEvent e) {
VirtualFile file = ShowFilePathAction.findLocalFile(e.getData(CommonDataKeys.VIRTUAL_FILE));
VirtualFile file = findLocalFile(e.getData(CommonDataKeys.VIRTUAL_FILE));
Presentation presentation = e.getPresentation();
presentation.setText(getActionName());
presentation.setEnabled(file != null);
}
@NotNull
public static String getActionName() {
return SystemInfo.isMac ? "Reveal in Finder" : "Show in " + ShowFilePathAction.getFileManagerName();
}
@Override
public void actionPerformed(@NotNull AnActionEvent e) {
VirtualFile file = ShowFilePathAction.findLocalFile(e.getData(CommonDataKeys.VIRTUAL_FILE));
VirtualFile file = findLocalFile(e.getData(CommonDataKeys.VIRTUAL_FILE));
if (file != null) {
ShowFilePathAction.openFile(new File(file.getPresentableUrl()));
openFile(new File(file.getPresentableUrl()));
}
}
}
public static boolean isSupported() {
return SystemInfo.isWindows || SystemInfo.isMac || SystemInfo.hasXdgOpen() ||
Desktop.isDesktopSupported() && Desktop.getDesktop().isSupported(Desktop.Action.OPEN);
}
@NotNull
public static String getActionName() {
return SystemInfo.isMac ? ActionsBundle.message("action.RevealIn.name.mac") : ActionsBundle.message("action.RevealIn.name.other", getFileManagerName());
}
@NotNull
public static String getFileManagerName() {
return fileManagerName.getValue();
}
@Nullable
public static VirtualFile findLocalFile(@Nullable VirtualFile file) {
if (file == null || file.isInLocalFileSystem()) {
return file;
}
VirtualFileSystem fs = file.getFileSystem();
if (fs instanceof ArchiveFileSystem && file.getParent() == null) {
return ((ArchiveFileSystem)fs).getLocalByEntry(file);
}
return null;
}
public static void showDialog(Project project, String message, String title, @NotNull File file, @Nullable DialogWrapper.DoNotAskOption option) {
String ok = getActionName();
String cancel = IdeBundle.message("action.close");
if (Messages.showOkCancelDialog(project, message, title, ok, cancel, Messages.getInformationIcon(), option) == Messages.OK) {
openFile(file);
}
}
/**
* Opens a system file manager with given file's parent directory open and the file highlighted in it
* (note that not all platforms support highlighting).
*/
public static void openFile(@NotNull File file) {
if (!file.exists()) {
LOG.info("does not exist: " + file);
return;
}
File parent = file.getAbsoluteFile().getParentFile();
if (parent != null) {
doOpen(parent, file);
}
else {
doOpen(file, null);
}
}
/**
* Opens a system file manager with given directory open in it.
*/
public static void openDirectory(@NotNull File directory) {
if (!directory.isDirectory()) {
LOG.info("not a directory: " + directory);
return;
}
doOpen(directory.getAbsoluteFile(), null);
}
private static void doOpen(@NotNull File _dir, @Nullable File _toSelect) {
String dir = FileUtil.toSystemDependentName(FileUtil.toCanonicalPath(_dir.getPath()));
String toSelect = _toSelect != null ? FileUtil.toSystemDependentName(FileUtil.toCanonicalPath(_toSelect.getPath())) : null;
if (SystemInfo.isWindows) {
spawn(toSelect != null ? "explorer /select,\"" + shortPath(toSelect) + '"' : "explorer /root,\"" + shortPath(dir) + '"');
}
else if (SystemInfo.isMac) {
if (toSelect != null) {
spawn("open", "-R", toSelect);
}
else {
spawn("open", dir);
}
}
else if (fileManagerApp.getValue() != null) {
spawn(fileManagerApp.getValue(), toSelect != null ? toSelect : dir);
}
else if (SystemInfo.hasXdgOpen()) {
spawn("xdg-open", dir);
}
else if (Desktop.isDesktopSupported() && Desktop.getDesktop().isSupported(Desktop.Action.OPEN)) {
LOG.debug("opening " + dir + " via Desktop API");
ApplicationManager.getApplication().executeOnPooledThread(() -> {
try {
Desktop.getDesktop().open(new File(dir));
}
catch (Exception e) {
LOG.warn(e);
}
});
}
else {
Messages.showErrorDialog("This action isn't supported on the current platform", "Cannot Open File");
}
}
private static String shortPath(String path) {
if (path.contains(" ") && JnaLoader.isLoaded()) {
// On the way from Runtime.exec() to CreateProcess(), a command line goes through couple rounds of merging and splitting
// which breaks paths containing a sequence of two or more spaces.
// Conversion to a short format is an ugly hack allowing to open such paths in Explorer.
char[] result = new char[WinDef.MAX_PATH];
if (Kernel32.INSTANCE.GetShortPathName(path, result, result.length) <= result.length) {
return Native.toString(result);
}
}
return path;
}
private static void spawn(String... command) {
LOG.debug(Arrays.toString(command));
ApplicationManager.getApplication().executeOnPooledThread(() -> {
try {
CapturingProcessHandler handler;
if (SystemInfo.isWindows) {
Process process = Runtime.getRuntime().exec(command[0]); // no quoting/escaping is needed
handler = new CapturingProcessHandler(process, null, command[0]);
}
else {
handler = new CapturingProcessHandler(new GeneralCommandLine(command));
}
handler.runProcess(10000, false).checkSuccess(LOG);
}
catch (Exception e) {
LOG.warn(e);
}
});
}
private static final NullableLazyValue<String> fileManagerApp = new AtomicNullableLazyValue<String>() {
@Override
protected String compute() {
return readDesktopEntryKey("Exec")
.map(line -> line.split(" ")[0])
.filter(exec -> exec.endsWith("nautilus") || exec.endsWith("pantheon-files"))
.orElse(null);
}
};
private static final NotNullLazyValue<String> fileManagerName = new AtomicNotNullLazyValue<String>() {
@NotNull
@Override
protected String compute() {
if (SystemInfo.isMac) return "Finder";
if (SystemInfo.isWindows) return "Explorer";
return readDesktopEntryKey("Name").orElse("File Manager");
}
};
private static Optional<String> readDesktopEntryKey(String key) {
if (SystemInfo.hasXdgMime()) {
String appName = ExecUtil.execAndReadLine(new GeneralCommandLine("xdg-mime", "query", "default", "inode/directory"));
if (appName != null && appName.endsWith(".desktop")) {
return Stream.of(getXdgDataDirectories().split(":"))
.map(dir -> new File(dir, "applications/" + appName))
.filter(File::exists)
.findFirst()
.map(file -> readDesktopEntryKey(file, key));
}
}
return Optional.empty();
}
private static String getXdgDataDirectories() {
String dataHome = System.getenv("XDG_DATA_HOME");
String dataDirs = System.getenv("XDG_DATA_DIRS");
return defaultIfEmpty(dataHome, SystemProperties.getUserHome() + "/.local/share") + ':' + defaultIfEmpty(dataDirs, "/usr/local/share:/usr/share");
}
private static String readDesktopEntryKey(File file, String key) {
LOG.debug("looking for '" + key + "' in " + file);
String prefix = key + '=';
try (BufferedReader reader = new BufferedReader(new InputStreamReader(new FileInputStream(file), StandardCharsets.UTF_8))) {
return reader.lines().filter(l -> l.startsWith(prefix)).map(l -> l.substring(prefix.length())).findFirst().orElse(null);
}
catch (IOException | UncheckedIOException e) {
LOG.info("Cannot read: " + file, e);
return null;
}
}
}
@@ -1,140 +1,51 @@
// Copyright 2000-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
package com.intellij.ide.actions;
import com.intellij.execution.configurations.GeneralCommandLine;
import com.intellij.execution.process.CapturingProcessHandler;
import com.intellij.execution.util.ExecUtil;
import com.intellij.ide.DataManager;
import com.intellij.ide.IdeBundle;
import com.intellij.idea.ActionsBundle;
import com.intellij.jna.JnaLoader;
import com.intellij.notification.Notification;
import com.intellij.notification.NotificationListener;
import com.intellij.openapi.actionSystem.AnActionEvent;
import com.intellij.openapi.actionSystem.CommonDataKeys;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.project.DumbAwareAction;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.ui.DialogWrapper;
import com.intellij.openapi.ui.Messages;
import com.intellij.openapi.ui.popup.JBPopupFactory;
import com.intellij.openapi.ui.popup.ListPopup;
import com.intellij.openapi.ui.popup.PopupStep;
import com.intellij.openapi.ui.popup.util.BaseListPopupStep;
import com.intellij.openapi.util.*;
import com.intellij.openapi.util.io.FileUtil;
import com.intellij.openapi.util.SystemInfo;
import com.intellij.openapi.vfs.JarFileSystem;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.openapi.vfs.VirtualFileSystem;
import com.intellij.openapi.vfs.newvfs.ArchiveFileSystem;
import com.intellij.ui.awt.RelativePoint;
import com.intellij.util.Consumer;
import com.intellij.util.SystemProperties;
import com.intellij.util.ui.EmptyIcon;
import com.sun.jna.Native;
import com.sun.jna.platform.win32.Kernel32;
import com.sun.jna.platform.win32.WinDef;
import org.jetbrains.annotations.ApiStatus;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import javax.swing.*;
import javax.swing.event.HyperlinkEvent;
import javax.swing.filechooser.FileSystemView;
import java.awt.*;
import java.awt.event.MouseEvent;
import java.io.*;
import java.net.URISyntaxException;
import java.net.URL;
import java.nio.charset.StandardCharsets;
import java.io.File;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Optional;
import java.util.stream.Stream;
import static com.intellij.openapi.util.text.StringUtil.defaultIfEmpty;
/**
* A rarely needed action that shows a popup with a path to a file (a list of parent directory names).
* Clicking/hitting enter on a directory opens it in a system file manager.
*
* @see RevealFileAction
*/
public class ShowFilePathAction extends DumbAwareAction {
private static final Logger LOG = Logger.getInstance(ShowFilePathAction.class);
public static final NotificationListener FILE_SELECTING_LISTENER = new NotificationListener.Adapter() {
@Override
protected void hyperlinkActivated(@NotNull Notification notification, @NotNull HyperlinkEvent e) {
URL url = e.getURL();
if (url != null) {
try {
openFile(new File(url.toURI()));
}
catch (URISyntaxException ex) {
LOG.warn("invalid URL: " + url, ex);
}
}
notification.expire();
}
};
private static final NullableLazyValue<String> fileManagerApp = new AtomicNullableLazyValue<String>() {
@Override
protected String compute() {
return readDesktopEntryKey("Exec")
.map(line -> line.split(" ")[0])
.filter(exec -> exec.endsWith("nautilus") || exec.endsWith("pantheon-files"))
.orElse(null);
}
};
private static final NotNullLazyValue<String> fileManagerName = new AtomicNotNullLazyValue<String>() {
@NotNull
@Override
protected String compute() {
if (SystemInfo.isMac) return "Finder";
if (SystemInfo.isWindows) return "Explorer";
return readDesktopEntryKey("Name").orElse("File Manager");
}
};
private static Optional<String> readDesktopEntryKey(String key) {
if (SystemInfo.hasXdgMime()) {
String appName = ExecUtil.execAndReadLine(new GeneralCommandLine("xdg-mime", "query", "default", "inode/directory"));
if (appName != null && appName.endsWith(".desktop")) {
return Stream.of(getXdgDataDirectories().split(":"))
.map(dir -> new File(dir, "applications/" + appName))
.filter(File::exists)
.findFirst()
.map(file -> readDesktopEntryKey(file, key));
}
}
return Optional.empty();
}
private static String getXdgDataDirectories() {
String dataHome = System.getenv("XDG_DATA_HOME");
String dataDirs = System.getenv("XDG_DATA_DIRS");
return defaultIfEmpty(dataHome, SystemProperties.getUserHome() + "/.local/share") + ':' + defaultIfEmpty(dataDirs, "/usr/local/share:/usr/share");
}
private static String readDesktopEntryKey(File file, String key) {
LOG.debug("looking for '" + key + "' in " + file);
String prefix = key + '=';
try (BufferedReader reader = new BufferedReader(new InputStreamReader(new FileInputStream(file), StandardCharsets.UTF_8))) {
return reader.lines().filter(l -> l.startsWith(prefix)).map(l -> l.substring(prefix.length())).findFirst().orElse(null);
}
catch (IOException | UncheckedIOException e) {
LOG.info("Cannot read: " + file, e);
return null;
}
}
@Override
public void update(@NotNull AnActionEvent e) {
boolean visible = !SystemInfo.isMac && isSupported();
boolean visible = !SystemInfo.isMac && RevealFileAction.isSupported();
e.getPresentation().setVisible(visible);
if (visible) {
VirtualFile file = getFile(e);
e.getPresentation().setEnabled(file != null);
e.getPresentation().setText(ActionsBundle.message("action.ShowFilePath.tuned", file != null && file.isDirectory() ? 1 : 0));
e.getPresentation().setText(ActionsBundle.message(file != null && file.isDirectory() ? "action.ShowFilePath.directory" : "action.ShowFilePath.file"));
}
}
@@ -166,7 +77,7 @@ public class ShowFilePathAction extends DumbAwareAction {
}
private static void show(@NotNull VirtualFile file, @NotNull Consumer<? super ListPopup> action) {
if (!isSupported()) return;
if (!RevealFileAction.isSupported()) return;
List<VirtualFile> files = new ArrayList<>();
List<String> fileUrls = new ArrayList<>();
@@ -202,15 +113,15 @@ public class ShowFilePathAction extends DumbAwareAction {
BaseListPopupStep<VirtualFile> step = new BaseListPopupStep<VirtualFile>(RevealFileAction.getActionName(), files, icons) {
@NotNull
@Override
public String getTextFor(final VirtualFile value) {
public String getTextFor(VirtualFile value) {
return value.getPresentableName();
}
@Override
public PopupStep onChosen(final VirtualFile selectedValue, final boolean finalChoice) {
final File selectedFile = new File(getPresentableUrl(selectedValue));
public PopupStep onChosen(VirtualFile selectedValue, boolean finalChoice) {
File selectedFile = new File(getPresentableUrl(selectedValue));
if (selectedFile.exists()) {
ApplicationManager.getApplication().executeOnPooledThread(() -> openFile(selectedFile));
ApplicationManager.getApplication().executeOnPooledThread(() -> RevealFileAction.openFile(selectedFile));
}
return FINAL_CHOICE;
}
@@ -219,142 +130,52 @@ public class ShowFilePathAction extends DumbAwareAction {
return JBPopupFactory.getInstance().createListPopup(step);
}
//<editor-fold desc="Deprecated stuff.">
/** @deprecated use {@link RevealFileAction#FILE_SELECTING_LISTENER} (to be removed in IDEA 2021.3) */
@Deprecated
@ApiStatus.ScheduledForRemoval(inVersion = "2021.3")
public static final NotificationListener FILE_SELECTING_LISTENER = RevealFileAction.FILE_SELECTING_LISTENER;
/** @deprecated use {@link RevealFileAction#isSupported} (to be removed in IDEA 2021.3) */
@Deprecated
@ApiStatus.ScheduledForRemoval(inVersion = "2021.3")
public static boolean isSupported() {
return SystemInfo.isWindows || SystemInfo.isMac || SystemInfo.hasXdgOpen() ||
Desktop.isDesktopSupported() && Desktop.getDesktop().isSupported(Desktop.Action.OPEN);
return RevealFileAction.isSupported();
}
@NotNull
public static String getFileManagerName() {
return fileManagerName.getValue();
/** @deprecated use {@link RevealFileAction#getFileManagerName} (to be removed in IDEA 2021.3) */
@Deprecated
@ApiStatus.ScheduledForRemoval(inVersion = "2021.3")
public static @NotNull String getFileManagerName() {
return RevealFileAction.getFileManagerName();
}
/**
* Shows system file manager with given file's parent directory open and the file highlighted in it<br/>
* (note that not all platforms support highlighting).
*
* @param file a file or directory to show and highlight in a file manager.
*/
/** @deprecated use {@link RevealFileAction#openFile} (to be removed in IDEA 2021.3) */
@Deprecated
@ApiStatus.ScheduledForRemoval(inVersion = "2021.3")
public static void openFile(@NotNull File file) {
if (!file.exists()) {
LOG.info("does not exist: " + file);
return;
}
File parent = file.getAbsoluteFile().getParentFile();
if (parent != null) {
doOpen(parent, file);
}
else {
doOpen(file, null);
}
RevealFileAction.openFile(file);
}
/**
* Shows system file manager with given directory open in it.
*
* @param directory a directory to open in a file manager.
*/
/** @deprecated use {@link RevealFileAction#openDirectory} (to be removed in IDEA 2021.3) */
@Deprecated
@ApiStatus.ScheduledForRemoval(inVersion = "2021.3")
public static void openDirectory(@NotNull File directory) {
if (!directory.isDirectory()) {
LOG.info("not a directory: " + directory);
return;
}
doOpen(directory.getAbsoluteFile(), null);
}
private static void doOpen(@NotNull File _dir, @Nullable File _toSelect) {
String dir = FileUtil.toSystemDependentName(FileUtil.toCanonicalPath(_dir.getPath()));
String toSelect = _toSelect != null ? FileUtil.toSystemDependentName(FileUtil.toCanonicalPath(_toSelect.getPath())) : null;
if (SystemInfo.isWindows) {
spawn(toSelect != null ? "explorer /select,\"" + shortPath(toSelect) + '"' : "explorer /root,\"" + shortPath(dir) + '"');
}
else if (SystemInfo.isMac) {
if (toSelect != null) {
spawn("open", "-R", toSelect);
}
else {
spawn("open", dir);
}
}
else if (fileManagerApp.getValue() != null) {
spawn(fileManagerApp.getValue(), toSelect != null ? toSelect : dir);
}
else if (SystemInfo.hasXdgOpen()) {
spawn("xdg-open", dir);
}
else if (Desktop.isDesktopSupported() && Desktop.getDesktop().isSupported(Desktop.Action.OPEN)) {
LOG.debug("opening " + dir + " via Desktop API");
ApplicationManager.getApplication().executeOnPooledThread(() -> {
try {
Desktop.getDesktop().open(new File(dir));
}
catch (Exception e) {
LOG.warn(e);
}
});
}
else {
Messages.showErrorDialog("This action isn't supported on the current platform", "Cannot Open File");
}
}
private static String shortPath(String path) {
if (path.contains(" ") && JnaLoader.isLoaded()) {
// On the way from Runtime.exec() to CreateProcess(), a command line goes through couple rounds of merging and splitting
// which breaks paths containing a sequence of two or more spaces.
// Conversion to a short format is an ugly hack allowing to open such paths in Explorer.
char[] result = new char[WinDef.MAX_PATH];
if (Kernel32.INSTANCE.GetShortPathName(path, result, result.length) <= result.length) {
return Native.toString(result);
}
}
return path;
}
private static void spawn(String... command) {
LOG.debug(Arrays.toString(command));
ApplicationManager.getApplication().executeOnPooledThread(() -> {
try {
CapturingProcessHandler handler;
if (SystemInfo.isWindows) {
Process process = Runtime.getRuntime().exec(command[0]); // no quoting/escaping is needed
handler = new CapturingProcessHandler(process, null, command[0]);
}
else {
handler = new CapturingProcessHandler(new GeneralCommandLine(command));
}
handler.runProcess(10000, false).checkSuccess(LOG);
}
catch (Exception e) {
LOG.warn(e);
}
});
RevealFileAction.openDirectory(directory);
}
/** @deprecated use {@link RevealFileAction#showDialog} (to be removed in IDEA 2021.3) */
@Deprecated
@ApiStatus.ScheduledForRemoval(inVersion = "2021.3")
public static void showDialog(Project project, String message, String title, @NotNull File file, @Nullable DialogWrapper.DoNotAskOption option) {
String ok = RevealFileAction.getActionName();
String cancel = IdeBundle.message("action.close");
if (Messages.showOkCancelDialog(project, message, title, ok, cancel, Messages.getInformationIcon(), option) == Messages.OK) {
openFile(file);
}
RevealFileAction.showDialog(project, message, title, file, option);
}
@Nullable
public static VirtualFile findLocalFile(@Nullable VirtualFile file) {
if (file == null || file.isInLocalFileSystem()) {
return file;
}
VirtualFileSystem fs = file.getFileSystem();
if (fs instanceof ArchiveFileSystem && file.getParent() == null) {
return ((ArchiveFileSystem)fs).getLocalByEntry(file);
}
return null;
/** @deprecated use {@link RevealFileAction#findLocalFile} (to be removed in IDEA 2021.3) */
@Deprecated
@ApiStatus.ScheduledForRemoval(inVersion = "2021.3")
public static @Nullable VirtualFile findLocalFile(@Nullable VirtualFile file) {
return RevealFileAction.findLocalFile(file);
}
//</editor-fold>
}
@@ -1,18 +1,4 @@
/*
* 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.
*/
// Copyright 2000-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
package com.intellij.ide.actions;
import com.intellij.openapi.actionSystem.AnAction;
@@ -35,18 +21,18 @@ public class ShowLogAction extends AnAction implements DumbAware {
@Override
public void actionPerformed(@NotNull AnActionEvent e) {
final File logFile = new File(PathManager.getLogPath(), "idea.log");
ShowFilePathAction.openFile(logFile);
RevealFileAction.openFile(logFile);
}
@Override
public void update(@NotNull AnActionEvent e) {
Presentation presentation = e.getPresentation();
presentation.setVisible(ShowFilePathAction.isSupported());
presentation.setVisible(RevealFileAction.isSupported());
presentation.setText(getActionName());
}
@NotNull
public static String getActionName() {
return "Show Log in " + ShowFilePathAction.getFileManagerName();
return "Show Log in " + RevealFileAction.getFileManagerName();
}
}
@@ -2,7 +2,7 @@
package com.intellij.internal.cachedValueProfiler;
import com.intellij.CommonBundle;
import com.intellij.ide.actions.ShowFilePathAction;
import com.intellij.ide.actions.RevealFileAction;
import com.intellij.notification.NotificationDisplayType;
import com.intellij.notification.NotificationGroup;
import com.intellij.notification.NotificationType;
@@ -31,8 +31,8 @@ public class DumpCachedValueProfilerInfoAction extends DumbAwareAction {
try {
File file = CachedValueProfilerDumper.dumpResults(new File(PathManager.getLogPath()));
String url = FileUtil.getUrl(file);
String message = CommonBundle.message("cached.value.snapshot.success", file, url, ShowFilePathAction.getFileManagerName());
GROUP.createNotification("", message, NotificationType.INFORMATION, ShowFilePathAction.FILE_SELECTING_LISTENER).notify(project);
String message = CommonBundle.message("cached.value.snapshot.success", file, url, RevealFileAction.getFileManagerName());
GROUP.createNotification("", message, NotificationType.INFORMATION, RevealFileAction.FILE_SELECTING_LISTENER).notify(project);
}
catch (IOException exception) {
GROUP.createNotification(CommonBundle.message("cached.value.snapshot.error", exception.getMessage()),
@@ -3,7 +3,7 @@ package com.intellij.openapi.vfs.impl.local;
import com.intellij.execution.process.OSProcessHandler;
import com.intellij.execution.process.ProcessOutputTypes;
import com.intellij.ide.actions.ShowFilePathAction;
import com.intellij.ide.actions.RevealFileAction;
import com.intellij.notification.NotificationListener;
import com.intellij.openapi.application.Application;
import com.intellij.openapi.application.ApplicationBundle;
@@ -80,7 +80,7 @@ public class NativeFileWatcherImpl extends PluggableFileWatcher {
}
else if (!myExecutable.canExecute()) {
String message = ApplicationBundle.message("watcher.exe.not.exe", myExecutable);
notifyOnFailure(message, (notification, event) -> ShowFilePathAction.openFile(myExecutable));
notifyOnFailure(message, (notification, event) -> RevealFileAction.openFile(myExecutable));
}
else {
try {
@@ -419,7 +419,8 @@ action.FileStructurePopup.text=F_ile Structure
action.FileStructurePopup.description=Popup structure of the current file for quick navigation
action.ShowFilePath.text=File _Path
action.ShowFilePath.description=Popup path of the current file for opening in external file manager
action.ShowFilePath.tuned={0,choice,0#File|1#Directory} _Path
action.ShowFilePath.file=SFile _Path
action.ShowFilePath.directory=Directory _Path
action.SelectIn.text=Se_lect In...
action.SelectIn.description=Select the current class or method in any view
action.FixDocComment.text=Fix doc comment
@@ -1576,6 +1577,8 @@ action.Console.History.Next.description=Next entry in console history
action.Console.History.Browse.text=Browse Console History
action.Console.History.Browse.description=Browse console history
action.RevealIn.description=Highlights the file in platform's file manager
action.RevealIn.name.mac=Reveal in Finder
action.RevealIn.name.other=Show in {0}
action.GoToLinkTarget.text=Go to Link Target
action.GoToLinkTarget.description=Opens a target of this symlink in the Project View
@@ -2,7 +2,7 @@
package com.intellij.openapi.vcs.changes.patch;
import com.intellij.CommonBundle;
import com.intellij.ide.actions.ShowFilePathAction;
import com.intellij.ide.actions.RevealFileAction;
import com.intellij.ide.util.PropertiesComponent;
import com.intellij.openapi.application.ModalityState;
import com.intellij.openapi.application.PathManager;
@@ -153,7 +153,7 @@ public class CreatePatchCommitExecutor extends LocalCommitExecutor implements Pr
WaitForProgressToShow.runOrInvokeLaterAboveProgress(() -> {
final VcsConfiguration configuration = VcsConfiguration.getInstance(myProject);
if (Boolean.TRUE.equals(configuration.SHOW_PATCH_IN_EXPLORER)) {
ShowFilePathAction.openFile(file);
RevealFileAction.openFile(file);
}
else if (configuration.SHOW_PATCH_IN_EXPLORER == null) {
configuration.SHOW_PATCH_IN_EXPLORER = showDialog(file);
@@ -232,7 +232,7 @@ public class CreatePatchCommitExecutor extends LocalCommitExecutor implements Pr
}
};
ShowFilePathAction.showDialog(myProject, message, title, file, option);
RevealFileAction.showDialog(myProject, message, title, file, option);
return ref[0];
}
@@ -1,7 +1,7 @@
// Copyright 2000-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
package com.intellij.openapi.vcs.configurable;
import com.intellij.ide.actions.ShowFilePathAction;
import com.intellij.ide.actions.RevealFileAction;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.Comparing;
import com.intellij.openapi.util.SystemInfo;
@@ -57,7 +57,7 @@ public class VcsGeneralConfigurationPanel {
myProject = project;
myOnPatchCreationLabel.setText(VcsBundle.message("combobox.show.patch.in.explorer.after.creation",
ShowFilePathAction.getFileManagerName()));
RevealFileAction.getFileManagerName()));
myOnFileAddingGroup = new JRadioButton[]{
myShowDialogOnAddingFile,
@@ -92,7 +92,7 @@ public class VcsGeneralConfigurationPanel {
myPromptsPanel.setSize(myPromptsPanel.getPreferredSize()); // todo check text!
myOnPatchCreation.setName((SystemInfo.isMac ? "Reveal patch in" : "Show patch in ") +
ShowFilePathAction.getFileManagerName() + " after creation:");
RevealFileAction.getFileManagerName() + " after creation:");
}
public void apply() {
@@ -4,7 +4,7 @@ package org.jetbrains.plugins.gradle.issue.quickfix
import com.intellij.build.SyncViewManager
import com.intellij.build.issue.BuildIssueQuickFix
import com.intellij.execution.executors.DefaultRunExecutor
import com.intellij.ide.actions.ShowFilePathAction
import com.intellij.ide.actions.RevealFileAction
import com.intellij.ide.actions.ShowLogAction
import com.intellij.openapi.application.PathManager
import com.intellij.openapi.diagnostic.logger
@@ -60,7 +60,7 @@ class GradleVersionQuickFix(private val projectPath: String,
.apply {
isBalloonNotification = true
balloonGroup = "Gradle Import"
setListener("#open_log") { _, _ -> ShowFilePathAction.openFile(File(PathManager.getLogPath(), "idea.log")) }
setListener("#open_log") { _, _ -> RevealFileAction.openFile(File(PathManager.getLogPath(), "idea.log")) }
}
ExternalSystemNotificationManager.getInstance(project).showNotification(GradleConstants.SYSTEM_ID, notification)
throw it
@@ -1,23 +1,9 @@
/*
* 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.
*/
// Copyright 2000-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
package org.jetbrains.idea.maven.project;
import com.intellij.execution.filters.Filter;
import com.intellij.execution.filters.HyperlinkInfo;
import com.intellij.ide.actions.ShowFilePathAction;
import com.intellij.ide.actions.RevealFileAction;
import com.intellij.openapi.project.Project;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -46,7 +32,7 @@ public class MavenTestConsoleFilter implements Filter {
public void navigate(Project project) {
File f = new File(path);
if (f.isDirectory()) {
ShowFilePathAction.openDirectory(f);
RevealFileAction.openDirectory(f);
}
}
});
@@ -1,21 +1,7 @@
/*
* Copyright 2000-2017 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
// Copyright 2000-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
package org.jetbrains.plugins.terminal.action;
import com.intellij.ide.actions.ShowFilePathAction;
import com.intellij.ide.actions.RevealFileAction;
import com.intellij.openapi.actionSystem.AnActionEvent;
import com.intellij.openapi.actionSystem.CommonDataKeys;
import com.intellij.openapi.project.DumbAwareAction;
@@ -37,7 +23,7 @@ public class RevealFileInTerminalAction extends DumbAwareAction {
@Nullable
private static VirtualFile getSelectedFile(@NotNull AnActionEvent e) {
return ShowFilePathAction.findLocalFile(e.getData(CommonDataKeys.VIRTUAL_FILE));
return RevealFileAction.findLocalFile(e.getData(CommonDataKeys.VIRTUAL_FILE));
}
@Override