Revert "drop MoveTerminalSessionToEditorAction"

This reverts commit 5403338dfadcd40f065b537a7101e0ffe35bdce1.

GitOrigin-RevId: 3db0426ce54b447d5d78492de6dcde6c7c565414
This commit is contained in:
Gregory.Shrago
2024-10-29 17:35:56 +04:00
committed by intellij-monorepo-bot
parent bfac111af4
commit 826de1168c
10 changed files with 409 additions and 6 deletions

View File

@@ -30,6 +30,9 @@
<action id="Terminal.RenameSession" class="org.jetbrains.plugins.terminal.action.RenameTerminalSessionAction">
<add-to-group group-id="ToolWindowContextMenu" anchor="last"/>
</action>
<action id="Terminal.MoveToEditor" class="org.jetbrains.plugins.terminal.action.MoveTerminalSessionToEditorAction">
<add-to-group group-id="ToolWindowContextMenu" anchor="last"/>
</action>
<action id="Terminal.SplitVertically" class="org.jetbrains.plugins.terminal.action.TerminalSplitActionBase$Vertical">
<add-to-group group-id="ToolWindowContextMenu" anchor="last"/>
</action>

View File

@@ -11,6 +11,8 @@
key="configurable.TerminalOptionsConfigurable.display.name"
id="terminal" instance="org.jetbrains.plugins.terminal.TerminalOptionsConfigurable"/>
<fileEditorProvider id="terminal-session-editor" implementation="org.jetbrains.plugins.terminal.vfs.TerminalSessionEditorProvider"/>
<applicationService serviceImplementation="org.jetbrains.plugins.terminal.TerminalOptionsProvider"/>
<applicationService serviceImplementation="org.jetbrains.plugins.terminal.arrangement.TerminalCommandHistoryManager"/>

View File

@@ -4,6 +4,7 @@ action.Terminal.CloseTab.text=Close Tab
action.Terminal.SwitchFocusToEditor.text=Switch Focus To Editor
action.Terminal.MoveToolWindowTabRight.text=Move Tab Right
action.Terminal.MoveToolWindowTabLeft.text=Move Tab Left
action.Terminal.MoveToEditor.text=Move to Editor
action.Terminal.RenameSession.text=Rename Session
action.Terminal.OpenInTerminal.text=Open in Terminal
action.Terminal.OpenInTerminal.RevealInPopup.text=Terminal

View File

@@ -41,9 +41,14 @@ import com.intellij.terminal.TerminalTitleListener;
import com.intellij.terminal.ui.TerminalWidget;
import com.intellij.terminal.ui.TerminalWidgetKt;
import com.intellij.toolWindow.InternalDecoratorImpl;
import com.intellij.ui.awt.RelativePoint;
import com.intellij.ui.awt.RelativeRectangle;
import com.intellij.ui.content.Content;
import com.intellij.ui.content.ContentFactory;
import com.intellij.ui.content.ContentManager;
import com.intellij.ui.docking.DockContainer;
import com.intellij.ui.docking.DockManager;
import com.intellij.ui.docking.DockableContent;
import com.intellij.util.ArrayUtil;
import com.intellij.util.ObjectUtils;
import com.intellij.util.PathUtil;
@@ -62,6 +67,7 @@ import org.jetbrains.plugins.terminal.arrangement.TerminalCommandHistoryManager;
import org.jetbrains.plugins.terminal.arrangement.TerminalWorkingDirectoryManager;
import org.jetbrains.plugins.terminal.block.BlockTerminalPromotionService;
import org.jetbrains.plugins.terminal.ui.TerminalContainer;
import org.jetbrains.plugins.terminal.vfs.TerminalSessionVirtualFileImpl;
import javax.swing.*;
import java.awt.event.ActionEvent;
@@ -82,6 +88,7 @@ public final class TerminalToolWindowManager implements Disposable {
private ToolWindow myToolWindow;
private final Project myProject;
private final AbstractTerminalRunner<?> myTerminalRunner;
private TerminalDockContainer myDockContainer;
private final Map<TerminalWidget, TerminalContainer> myContainerByWidgetMap = new HashMap<>();
@NotNull
@@ -151,6 +158,11 @@ public final class TerminalToolWindowManager implements Disposable {
}
}
});
if (myDockContainer == null) {
myDockContainer = new TerminalDockContainer();
DockManager.getInstance(myProject).register(myDockContainer, toolWindow.getDisposable());
}
}
void restoreTabs(@Nullable TerminalArrangementState arrangementState) {
@@ -173,7 +185,7 @@ public final class TerminalToolWindowManager implements Disposable {
}
public void createNewSession(@NotNull AbstractTerminalRunner<?> terminalRunner, @Nullable TerminalTabState tabState) {
createNewSession(terminalRunner, tabState, true, true);
createNewSession(terminalRunner, tabState, true);
}
public @NotNull TerminalWidget createNewSession() {
@@ -220,10 +232,16 @@ public final class TerminalToolWindowManager implements Disposable {
return createNewSession(myTerminalRunner, tabState, requestFocus, deferSessionStartUntilUiShown);
}
private void createNewSession(@NotNull AbstractTerminalRunner<?> terminalRunner,
@Nullable TerminalTabState tabState,
boolean requestFocus) {
createNewSession(terminalRunner, tabState, requestFocus, true);
}
private @NotNull TerminalWidget createNewSession(@NotNull AbstractTerminalRunner<?> terminalRunner,
@Nullable TerminalTabState tabState,
boolean requestFocus,
boolean deferSessionStartUntilUiShown) {
@Nullable TerminalTabState tabState,
boolean requestFocus,
boolean deferSessionStartUntilUiShown) {
ToolWindow toolWindow = getOrInitToolWindow();
Content content = createNewTab(null, terminalRunner, toolWindow, tabState, requestFocus, deferSessionStartUntilUiShown);
return Objects.requireNonNull(content.getUserData(TERMINAL_WIDGET_KEY));
@@ -325,7 +343,7 @@ public final class TerminalToolWindowManager implements Disposable {
else {
state.setDefaultTitle(tabState.myTabName);
}
return Unit.INSTANCE;
return null;
});
}
updateTabTitle(widget.getTerminalTitle(), toolWindow, content);
@@ -474,7 +492,7 @@ public final class TerminalToolWindowManager implements Disposable {
content.setDisplayName(generatedName);
terminalTitle.change((state) -> {
state.setDefaultTitle(generatedName);
return Unit.INSTANCE;
return null;
});
}
@@ -601,6 +619,16 @@ public final class TerminalToolWindowManager implements Disposable {
return content.getUserData(RUNNER_KEY);
}
public void detachWidgetAndRemoveContent(@NotNull Content content) {
ContentManager contentManager = myToolWindow.getContentManager();
LOG.assertTrue(contentManager.getIndexOfContent(content) >= 0, "Not a terminal content");
TerminalTabCloseListener.Companion.executeContentOperationSilently(content, () -> {
contentManager.removeContent(content, true);
return Unit.INSTANCE;
});
content.putUserData(TERMINAL_WIDGET_KEY, null);
}
public static boolean isInTerminalToolWindow(@NotNull JBTerminalWidget widget) {
DataContext dataContext = DataManager.getInstance().getDataContext(widget.getTerminalPanel());
ToolWindow toolWindow = dataContext.getData(PlatformDataKeys.TOOL_WINDOW);
@@ -610,6 +638,49 @@ public final class TerminalToolWindowManager implements Disposable {
public static boolean isTerminalToolWindow(@Nullable ToolWindow toolWindow) {
return toolWindow != null && TerminalToolWindowFactory.TOOL_WINDOW_ID.equals(toolWindow.getId());
}
private final class TerminalDockContainer implements DockContainer {
@NotNull
@Override
public RelativeRectangle getAcceptArea() {
return new RelativeRectangle(myToolWindow.getComponent());
}
@NotNull
@Override
public ContentResponse getContentResponse(@NotNull DockableContent content, RelativePoint point) {
return isTerminalSessionContent(content) ? ContentResponse.ACCEPT_MOVE : ContentResponse.DENY;
}
@Override
public @NotNull JComponent getContainerComponent() {
return myToolWindow.getComponent();
}
@Override
public void add(@NotNull DockableContent content, RelativePoint dropTarget) {
if (isTerminalSessionContent(content)) {
TerminalSessionVirtualFileImpl terminalFile = (TerminalSessionVirtualFileImpl)content.getKey();
String name = terminalFile.getName();
Content newContent = newTab(myToolWindow, terminalFile.getTerminalWidget());
newContent.setDisplayName(name);
}
}
private static boolean isTerminalSessionContent(@NotNull DockableContent<?> content) {
return content.getKey() instanceof TerminalSessionVirtualFileImpl;
}
@Override
public boolean isEmpty() {
return false;
}
@Override
public boolean isDisposeWhenEmpty() {
return false;
}
}
}

View File

@@ -0,0 +1,34 @@
// Copyright 2000-2020 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.openapi.actionSystem.AnActionEvent
import com.intellij.openapi.fileEditor.FileEditorManager
import com.intellij.openapi.fileEditor.impl.FileEditorManagerImpl
import com.intellij.openapi.project.DumbAware
import com.intellij.openapi.project.Project
import com.intellij.terminal.JBTerminalWidget
import com.intellij.terminal.ui.TerminalWidget
import com.intellij.ui.content.Content
import org.jetbrains.plugins.terminal.TerminalToolWindowManager
import org.jetbrains.plugins.terminal.vfs.TerminalEditorWidgetListener
import org.jetbrains.plugins.terminal.vfs.TerminalSessionVirtualFileImpl
private class MoveTerminalSessionToEditorAction : TerminalSessionContextMenuActionBase(), DumbAware {
override fun updateInTerminalToolWindow(e: AnActionEvent, project: Project, content: Content, terminalWidget: TerminalWidget) {
e.presentation.isEnabledAndVisible = !TerminalToolWindowManager.getInstance(project).isSplitTerminal(terminalWidget)
}
override fun actionPerformedInTerminalToolWindow(e: AnActionEvent, project: Project, content: Content, terminalWidget: TerminalWidget) {
val terminalToolWindowManager = TerminalToolWindowManager.getInstance(project)
val file = TerminalSessionVirtualFileImpl(terminalWidget.terminalTitle.buildTitle(), terminalWidget, terminalToolWindowManager.terminalRunner.settingsProvider)
file.putUserData(FileEditorManagerImpl.CLOSING_TO_REOPEN, java.lang.Boolean.TRUE)
FileEditorManager.getInstance(project).openFile(file, true).first()
JBTerminalWidget.asJediTermWidget(terminalWidget)?.let {
it.listener = TerminalEditorWidgetListener(project, file)
}
terminalToolWindowManager.detachWidgetAndRemoveContent(content)
file.putUserData(FileEditorManagerImpl.CLOSING_TO_REOPEN, null)
}
}

View File

@@ -0,0 +1,27 @@
// 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.vfs
import com.intellij.openapi.fileEditor.FileEditorManager
import com.intellij.openapi.project.Project
import com.intellij.terminal.JBTerminalWidgetListener
class TerminalEditorWidgetListener(val project: Project, val file: TerminalSessionVirtualFileImpl): JBTerminalWidgetListener {
override fun onNewSession() {
}
override fun onTerminalStarted() {
}
override fun onPreviousTabSelected() {
}
override fun onNextTabSelected() {
}
override fun onSessionClosed() {
FileEditorManager.getInstance(project).closeFile(file)
}
override fun showTabs() {
}
}

View File

@@ -0,0 +1,124 @@
// Copyright 2000-2022 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
package org.jetbrains.plugins.terminal.vfs;
import com.intellij.openapi.Disposable;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.fileEditor.FileEditor;
import com.intellij.openapi.fileEditor.FileEditorManager;
import com.intellij.openapi.fileEditor.FileEditorState;
import com.intellij.openapi.fileEditor.ex.FileEditorManagerEx;
import com.intellij.openapi.fileEditor.impl.FileEditorManagerImpl;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.Disposer;
import com.intellij.openapi.util.UserDataHolderBase;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.terminal.JBTerminalWidget;
import com.intellij.terminal.TerminalTitle;
import com.intellij.terminal.TerminalTitleListener;
import com.intellij.terminal.ui.TerminalWidgetKt;
import com.jediterm.terminal.ui.TerminalWidgetListener;
import org.jetbrains.annotations.NotNull;
import javax.swing.*;
import java.beans.PropertyChangeListener;
import java.io.IOException;
public final class TerminalSessionEditor extends UserDataHolderBase implements FileEditor {
private static final Logger LOG = Logger.getInstance(TerminalSessionEditor.class);
private final Project myProject;
private final TerminalSessionVirtualFileImpl myFile;
private final TerminalWidgetListener myListener;
private final Disposable myWidgetParentDisposable = Disposer.newDisposable("terminal widget parent");
public TerminalSessionEditor(Project project, @NotNull TerminalSessionVirtualFileImpl terminalFile) {
myProject = project;
myFile = terminalFile;
TerminalWidgetKt.setNewParentDisposable(terminalFile.getTerminalWidget(), myWidgetParentDisposable);
myListener = widget -> {
ApplicationManager.getApplication().invokeLater(() -> {
FileEditorManagerEx.getInstanceEx(myProject).closeFile(myFile);
}, myProject.getDisposed());
};
JBTerminalWidget termWidget = JBTerminalWidget.asJediTermWidget(myFile.getTerminalWidget());
if (termWidget != null) {
termWidget.addListener(myListener);
}
terminalFile.getTerminalWidget().getTerminalTitle().addTitleListener(new TerminalTitleListener() {
@Override
public void onTitleChanged(@NotNull TerminalTitle terminalTitle) {
try {
terminalFile.rename(null, terminalTitle.buildTitle());
}
catch (IOException exception) {
throw new RuntimeException("Cannot rename");
}
FileEditorManager.getInstance(project).updateFilePresentation(terminalFile);
}
}, this);
}
@Override
public @NotNull JComponent getComponent() {
return myFile.getTerminalWidget().getComponent();
}
@Override
public @NotNull JComponent getPreferredFocusedComponent() {
return myFile.getTerminalWidget().getPreferredFocusableComponent();
}
@Override
public @NotNull String getName() {
return myFile.getName();
}
@Override
public void setState(@NotNull FileEditorState state) { }
@Override
public boolean isModified() {
return false;
}
@Override
public boolean isValid() {
return true;
}
@Override
public void addPropertyChangeListener(@NotNull PropertyChangeListener listener) { }
@Override
public void removePropertyChangeListener(@NotNull PropertyChangeListener listener) { }
@Override
public @NotNull VirtualFile getFile() {
return myFile;
}
@Override
public void dispose() {
JBTerminalWidget termWidget = JBTerminalWidget.asJediTermWidget(myFile.getTerminalWidget());
if (termWidget != null) {
termWidget.removeListener(myListener);
}
if (Boolean.TRUE.equals(myFile.getUserData(FileEditorManagerImpl.CLOSING_TO_REOPEN))) {
ApplicationManager.getApplication().invokeLater(() -> {
boolean disposedBefore = Disposer.isDisposed(myFile.getTerminalWidget());
Disposer.dispose(myWidgetParentDisposable);
boolean disposedAfter = Disposer.isDisposed(myFile.getTerminalWidget());
if (disposedBefore != disposedAfter) {
LOG.error(JBTerminalWidget.class.getSimpleName() + " parent disposable hasn't been changed " +
"(disposed before: " + disposedBefore + ", disposed after: " + disposedAfter + ")");
}
});
}
else {
Disposer.dispose(myWidgetParentDisposable);
}
}
}

View File

@@ -0,0 +1,65 @@
// Copyright 2000-2023 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
package org.jetbrains.plugins.terminal.vfs;
import com.intellij.openapi.Disposable;
import com.intellij.openapi.fileEditor.FileEditor;
import com.intellij.openapi.fileEditor.FileEditorPolicy;
import com.intellij.openapi.fileEditor.FileEditorProvider;
import com.intellij.openapi.fileEditor.impl.FileEditorManagerImpl;
import com.intellij.openapi.project.DumbAware;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.Disposer;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.terminal.ui.TerminalWidget;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.plugins.terminal.LocalBlockTerminalRunner;
import org.jetbrains.plugins.terminal.ShellStartupOptions;
import org.jetbrains.plugins.terminal.ShellStartupOptionsKt;
import org.jetbrains.plugins.terminal.arrangement.TerminalWorkingDirectoryManager;
final class TerminalSessionEditorProvider implements FileEditorProvider, DumbAware {
@Override
public boolean accept(@NotNull Project project, @NotNull VirtualFile file) {
return file instanceof TerminalSessionVirtualFileImpl;
}
@Override
public boolean acceptRequiresReadAction() {
return false;
}
@NotNull
@Override
public FileEditor createEditor(@NotNull Project project, @NotNull VirtualFile file) {
TerminalSessionVirtualFileImpl terminalFile = (TerminalSessionVirtualFileImpl)file;
if (file.getUserData(FileEditorManagerImpl.CLOSING_TO_REOPEN) != null) {
return new TerminalSessionEditor(project, terminalFile);
}
else {
TerminalWidget widget = terminalFile.getTerminalWidget();
String workingDirectory = TerminalWorkingDirectoryManager.getWorkingDirectory(widget);
Disposable tempDisposable = Disposer.newDisposable();
ShellStartupOptions options = ShellStartupOptionsKt.shellStartupOptions(workingDirectory);
TerminalWidget newWidget = new LocalBlockTerminalRunner(project).startShellTerminalWidget(tempDisposable, options, true);
TerminalSessionVirtualFileImpl newSessionVirtualFile = new TerminalSessionVirtualFileImpl(terminalFile.getName(),
newWidget,
terminalFile.getSettingsProvider());
TerminalSessionEditor editor = new TerminalSessionEditor(project, newSessionVirtualFile);
Disposer.dispose(tempDisposable); // newWidget's parent disposable should be changed now
return editor;
}
}
@NotNull
@Override
public String getEditorTypeId() {
return "terminal-session-editor";
}
@NotNull
@Override
public FileEditorPolicy getPolicy() {
return FileEditorPolicy.HIDE_DEFAULT_EDITOR;
}
}

View File

@@ -0,0 +1,39 @@
// Copyright 2000-2020 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.vfs;
import com.intellij.openapi.fileTypes.ex.FakeFileType;
import com.intellij.openapi.vfs.VirtualFile;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.plugins.terminal.TerminalIcons;
import javax.swing.*;
public final class TerminalSessionFileType extends FakeFileType {
public final static TerminalSessionFileType INSTANCE = new TerminalSessionFileType();
private TerminalSessionFileType() {
}
@Override
@NotNull
public String getName() {
return "Terminal Session";
}
@Override
@NotNull
public String getDescription() {
return getName() + " Fake File Type"; //NON-NLS
}
@Override
public Icon getIcon() {
return TerminalIcons.OpenTerminal_13x13;
}
@Override
public boolean isMyFileType(@NotNull VirtualFile file) {
return file instanceof TerminalSessionVirtualFileImpl;
}
}

View File

@@ -0,0 +1,37 @@
// Copyright 2000-2020 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.vfs;
import com.intellij.terminal.ui.TerminalWidget;
import com.intellij.testFramework.LightVirtualFile;
import com.jediterm.terminal.ui.settings.SettingsProvider;
import org.jetbrains.annotations.NotNull;
import java.io.IOException;
public final class TerminalSessionVirtualFileImpl extends LightVirtualFile {
private final TerminalWidget myTerminalWidget;
private final SettingsProvider mySettingsProvider;
public TerminalSessionVirtualFileImpl(@NotNull String name,
@NotNull TerminalWidget terminalWidget,
@NotNull SettingsProvider settingsProvider) {
myTerminalWidget = terminalWidget;
mySettingsProvider = settingsProvider;
setFileType(TerminalSessionFileType.INSTANCE);
setWritable(true);
try {
rename(null, name);
}
catch (IOException e) {
throw new RuntimeException("Cannot rename");
}
}
public @NotNull TerminalWidget getTerminalWidget() {
return myTerminalWidget;
}
public @NotNull SettingsProvider getSettingsProvider() {
return mySettingsProvider;
}
}