Repository: microsoft/terminal (language: cpp)

Issue:
Implement a keybinding to restart/reload a tab
<!-- 
🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨

I ACKNOWLEDGE THE FOLLOWING BEFORE PROCEEDING:
1. If I delete this entire template and go my own path, the core team may close my issue without further explanation or engagement.
2. If I list multiple bugs/concerns in this one issue, the core team may close my issue without further explanation or engagement.
3. If I write an issue that has many duplicates, the core team may close my issue without further explanation or engagement (and without necessarily spending time to find the exact duplicate ID number).
4. If I leave the title incomplete when filing the issue, the core team may close my issue without further explanation or engagement.
5. If I file something completely blank in the body, the core team may close my issue without further explanation or engagement.

All good? Then proceed!
-->

# Description of the new feature/enhancement

ConEmu has a default binding of Win+tilde to reload/restart the current tab.  This would be a useful feature to add to Windows Terminal, specifically to resolve issues whereby a fresh start of a tab is useful (eg: crashes, troubleshooting).

<!-- 
A clear and concise description of what the problem is that the new feature would solve.
Describe why and how a user would use this new functionality (if applicable).
-->



Discussion / hints:
Yea, I guess I could see that being useful. Thanks for the suggestion!
Agreed! Just want to add a concrete example:
You make a change on ~/.bashrc (or similar things) and don't want to do a source ... but a simple tab realod.
I mean, you could just `exec bash -li`. Terminal would destroy the process tree and relaunch it; is that really what you want instead of just sourcing your `.bashrc` again?
I think there is no definitive answer to your question but imho a relaunch as you described it would often be good enough and with a keybinding the comfort wins :)
Hey I'm gonna cross-link a pair of issues:
* This would be a good idea to include in the context menu, #1912
* This could be built directly into the connection somehow? With #4379 perhaps?
FWIW; I use Terminal tabs to ssh to other hosts a lot. When those ssh connections get dropped - e.g. I reboot the remote host, or there's some sort of network interruption - I keep wishing I could right-click on the tab and select a "restart" option of some sort, rather than having to close the dead tab, open a new one, then drag it to the position the old one was occupying. 
+1 for this feature - being able to <kbd>ctrl</kbd>+<kbd>r</kbd> an SSH session would be super useful!
@bbeckford If you'd like to "+1" this feature, the best way to do that is by hitting the 👍 button on this issue

![image](https://user-images.githubusercontent.com/18356694/96140789-ef3c8880-0ec5-11eb-82e0-30ce4977b9a7.png)

That way, you avoid unnecessarily pinging everyone following this thread. Thanks!
I would like this for both tabs and panes.  I encounter this issue with PowerShell.  It will stop outputting data to the screen (unknown cause), or the remote sessions will get hosed because the temp files are deleted.   Reconnecting the remote sessions don't work so restarting the shell seems to be the only fix.  I also encounter this if PS or some other process inside starts consuming too much memory, or the shell becomes unresponsive due to whatever abuse I'm hurling at it.  I tend to have consoles open for days, even weeks at a time, so this happens "regularly" for me.
If anyone is interested in a quick solution, I posted in #4379 a quick hack to get this functionality working in Windows Terminal here:

https://github.com/microsoft/terminal/issues/4379#issuecomment-905112832
I would love to see this particular feature prioritized. It's an incredible quality of life update that would drive a huge amount of impact from the users perspective.
Its a bit of a stretch and might not be perfect, but with https://github.com/microsoft/terminal/issues/960 just merged, you could add the following action to "restart" a tab

```
        { 
          "command": {
            "action": "multipleActions",
            "actions": [ 
                "closeTab",
                "restoreLastClosed"
            ]
            },
          "name": "Restart tab"
        },
```

This does what it says and closes the tab and then creates a new tab with the same settings as the last closed tab. Replace `closeTab` with `closePane` if you want to restart a single pane (at the time of writing the `closePane` version is buggy and doesn't work as part of multipleActions as expected).
My usecase from #12232 (dupe of this one):

"When ssh hangs in WSLv1 (usually because of network issues or after laptop sleep / hibernate), somehow it doesn't react to any Ctrl+C, Ctrl+Z. Then it's impossible to kill the ssh process, and it can take a few minutes for it to bail out by itself.

Current workaround: kill the whole tab (as it's impossible to kill the current process), open a new tab

Feature request: "reset a tab" command that will restart the tab (and preserve the tab's place in the tab bar).

Alternative feature request: somehow detecting the current process in the bash session and providing a command to kill it, e.g. it could kill all child processes except the original bash process PID."
My usecase:
open an ssh session and start screen on that, start a job in screen and let it run.
I want to reload the ssh session so that screen can continue in background, and I come back to new ssh session in same tab
When ever I want I can go back to my screen from new session.

I know screen has option to exit without terminating, but being iterm user on mac, I find it more convenient to just reload the tab instead.

> Its a bit of a stretch and might not be perfect, but with #960 just merged, you could add the following action to "restart" a tab
> 
> ```
>         { 
>           "command": {
>             "action": "multipleActions",
>             "actions": [ 
>                 "closeTab",
>                 "restoreLastClosed"
>             ]
>             },
>           "name": "Restart tab"
>         },
> ```
> 
> This does what it says and closes the tab and then creates a new tab with the same settings as the last closed tab. Replace `closeTab` with `closePane` if you want to restart a single pane (at the time of writing the `closePane` version is buggy and doesn't work as part of multipleActions as expected).

The problem with this is the tab position is not restored, if tab closed is first one, the restored tab is the last one.
the position should also be restored
> Its a bit of a stretch and might not be perfect, but with #960 just merged, you could add the following action to "restart" a tab
> 
> ```
>         { 
>           "command": {
>             "action": "multipleActions",
>             "actions": [ 
>                 "closeTab",
>                 "restoreLastClosed"
>             ]
>             },
>           "name": "Restart tab"
>         },
> ```
> 
> This does what it says and closes the tab and then creates a new tab with the same settings as the last closed tab. Replace `closeTab` with `closePane` if you want to restart a single pane (at the time of writing the `closePane` version is buggy and doesn't work as part of multipleActions as expected).

In case there is only one tab left, the whole window will be closed directly, and I found that this problem can be solved by `split pane` command.
```json
        {
            "command": 
            {
                "action": "multipleActions",
                "actions": 
                [
                    {
                        "action": "splitPane",
                        "size":0.1,
                        "split": "up",
                        "splitMode":"duplicate"
                    },
                    {
                        "action": "moveFocus",
                        "direction": "previous"
                    },
                    {
                        "action": "closePane"
                    }

                ]
            },
            "keys": "ctrl+r",
            "name": "restart tab"
        }
```
I think this method is close to perfect, except when closing the pane, it shows the content behind the terminal, which may be a rendering engine issue. I made the newly added pane as large as possible (by setting `size` to 0.1) to minimize its impact.

**In addition, the most important thing is that this method does not require an update to the preview version.**
I think 

> > 它有点牵强，可能并不完美，但#960刚刚合并，您可以添加以下操作来“重新启动”选项卡
> > ```
> >         { 
> >           "command": {
> >             "action": "multipleActions",
> >             "actions": [ 
> >                 "closeTab",
> >                 "restoreLastClosed"
> >             ]
> >             },
> >           "name": "Restart tab"
> >         },
> > ```
> > 
> > 
> >     
> >       
> >     
> > 
> >       
> >     
> > 
> >     
> >   
> > 这会执行它所说的并关闭选项卡，然后创建一个与上次关闭的选项卡具有相同设置的新选项卡。如果要重新启动单个窗格，请替换`closeTab`为（在编写该版本时存在错误，并且不能按预期作为 multipleActions 的一部分工作）。`closePane``closePane`
> 
> 如果只剩下一个tab，直接关闭整个窗口，我发现这个问题可以通过`split pane`命令解决。
> 
> ```json
>         {
>             "command": 
>             {
>                 "action": "multipleActions",
>                 "actions": 
>                 [
>                     {
>                         "action": "splitPane",
>                         "size":0.1,
>                         "split": "up",
>                         "splitMode":"duplicate"
>                     },
>                     {
>                         "action": "moveFocus",
>                         "direction": "previous"
>                     },
>                     {
>                         "action": "closePane"
>                     }
> 
>                 ]
>             },
>             "keys": "ctrl+r",
>             "name": "restart tab"
>         }
> ```
> 
> 我认为这种方法接近完美，除了关闭窗格时，它显示了终端后面的内容，这可能是渲染引擎的问题。我使新添加的窗格尽可能大（通过设置`size`为 0.1）以最大程度地减少其影响。
> 
> **另外，最重要的是这种方法不需要更新到预览版。**

Thanks for your answer! but I think it is not perfect, I just want to reopen this SSH quickly, but the "ctrl + r" will do 3 actions include spliting and closing  the original pane  ,and there is a dividing line will flash quickly.
![image](https://user-images.githubusercontent.com/55246033/183937819-90316aa8-a220-4cfb-b17e-12aa74e49405.png)

I found a solution (maybe perfect?)

```
        {
            "command": 
            {
                "action": "multipleActions",
                "actions": 
                [
                    "duplicateTab",
                    {
                        "action": "prevTab"
                    },
                    {
                        "action": "closeTab"
                    }
                ]
            },
            "keys": "ctrl+shift+r",
            "name": "Restart tab"
        }
```

and set "Position of newly created tabs" to "After current tab" in Appearance

Fix patch:
diff --git a/src/cascadia/TerminalApp/AppActionHandlers.cpp b/src/cascadia/TerminalApp/AppActionHandlers.cpp
index 7d1e1178ddb..43fa9630a6a 100644
--- a/src/cascadia/TerminalApp/AppActionHandlers.cpp
+++ b/src/cascadia/TerminalApp/AppActionHandlers.cpp
@@ -1228,4 +1228,17 @@ namespace winrt::TerminalApp::implementation
             args.Handled(handled);
         }
     }
+
+    void TerminalPage::_HandleRestartConnection(const IInspectable& /*sender*/,
+                                                const ActionEventArgs& args)
+    {
+        if (const auto activeTab{ _GetFocusedTabImpl() })
+        {
+            if (const auto activePane{ activeTab->GetActivePane() })
+            {
+                _restartPaneConnection(activePane);
+            }
+        }
+        args.Handled(true);
+    }
 }
diff --git a/src/cascadia/TerminalApp/TerminalPage.cpp b/src/cascadia/TerminalApp/TerminalPage.cpp
index c4561e9364c..99a1fdafde9 100644
--- a/src/cascadia/TerminalApp/TerminalPage.cpp
+++ b/src/cascadia/TerminalApp/TerminalPage.cpp
@@ -2979,18 +2979,20 @@ namespace winrt::TerminalApp::implementation
             original->SetActive();
         }
 
-        resultPane->RestartTerminalRequested([this](const auto& pane) {
-            auto connection = _duplicateConnectionForRestart(pane);
-            if (connection)
-            {
-                pane->GetTerminalControl().Connection(connection);
-                connection.Start();
-            }
-        });
+        resultPane->RestartTerminalRequested({ get_weak(), &TerminalPage::_restartPaneConnection });
 
         return resultPane;
     }
 
+    void TerminalPage::_restartPaneConnection(const std::shared_ptr<Pane>& pane)
+    {
+        if (const auto& connection{ _duplicateConnectionForRestart(pane) })
+        {
+            pane->GetTerminalControl().Connection(connection);
+            connection.Start();
+        }
+    }
+
     // Method Description:
     // - Sets background image and applies its settings (stretch, opacity and alignment)
     // - Checks path validity
diff --git a/src/cascadia/TerminalApp/TerminalPage.h b/src/cascadia/TerminalApp/TerminalPage.h
index da694f50ed5..867e93eece3 100644
--- a/src/cascadia/TerminalApp/TerminalPage.h
+++ b/src/cascadia/TerminalApp/TerminalPage.h
@@ -295,6 +295,7 @@ namespace winrt::TerminalApp::implementation
         void _CreateNewTabFromPane(std::shared_ptr<Pane> pane, uint32_t insertPosition = -1);
         winrt::Microsoft::Terminal::TerminalConnection::ITerminalConnection _CreateConnectionFromSettings(Microsoft::Terminal::Settings::Model::Profile profile, Microsoft::Terminal::Settings::Model::TerminalSettings settings, const bool inheritCursor);
         winrt::Microsoft::Terminal::TerminalConnection::ITerminalConnection _duplicateConnectionForRestart(std::shared_ptr<Pane> pane);
+        void _restartPaneConnection(const std::shared_ptr<Pane>& pane);
 
         winrt::fire_and_forget _OpenNewWindow(const Microsoft::Terminal::Settings::Model::NewTerminalArgs newTerminalArgs);
 
diff --git a/src/cascadia/TerminalSettingsModel/ActionAndArgs.cpp b/src/cascadia/TerminalSettingsModel/ActionAndArgs.cpp
index 8b5613bd006..3efeb81d5b7 100644
--- a/src/cascadia/TerminalSettingsModel/ActionAndArgs.cpp
+++ b/src/cascadia/TerminalSettingsModel/ActionAndArgs.cpp
@@ -90,6 +90,7 @@ static constexpr std::string_view ToggleBlockSelectionKey{ "toggleBlockSelection
 static constexpr std::string_view SwitchSelectionEndpointKey{ "switchSelectionEndpoint" };
 static constexpr std::string_view ColorSelectionKey{ "experimental.colorSelection" };
 static constexpr std::string_view ExpandSelectionToWordKey{ "expandSelectionToWord" };
+static constexpr std::string_view RestartConnectionKey{ "restartConnection" };
 
 static constexpr std::string_view ActionKey{ "action" };
 
@@ -418,6 +419,7 @@ namespace winrt::Microsoft::Terminal::Settings::Model::implementation
                 { ShortcutAction::SwitchSelectionEndpoint, RS_(L"SwitchSelectionEndpointCommandKey") },
                 { ShortcutAction::ColorSelection, MustGenerate },
                 { ShortcutAction::ExpandSelectionToWord, RS_(L"ExpandSelectionToWordCommandKey") },
+                { ShortcutAction::RestartConnection, RS_(L"RestartConnectionKey") },
             };
         }();
 
diff --git a/src/cascadia/TerminalSettingsModel/AllShortcutActions.h b/src/cascadia/TerminalSettingsModel/AllShortcutActions.h
index fd6f1a080e2..b6a2228b88c 100644
--- a/src/cascadia/TerminalSettingsModel/AllShortcutActions.h
+++ b/src/cascadia/TerminalSettingsModel/AllShortcutActions.h
@@ -103,7 +103,8 @@
     ON_ALL_ACTIONS(SwitchSelectionEndpoint) \
     ON_ALL_ACTIONS(ColorSelection)          \
     ON_ALL_ACTIONS(ExpandSelectionToWord)   \
-    ON_ALL_ACTIONS(CloseOtherPanes)
+    ON_ALL_ACTIONS(CloseOtherPanes)         \
+    ON_ALL_ACTIONS(RestartConnection)
 
 #define ALL_SHORTCUT_ACTIONS_WITH_ARGS             \
     ON_ALL_ACTIONS_WITH_ARGS(AdjustFontSize)       \
diff --git a/src/cascadia/TerminalSettingsModel/Resources/en-US/Resources.resw b/src/cascadia/TerminalSettingsModel/Resources/en-US/Resources.resw
index a64259f182d..1d6502c1f7a 100644
--- a/src/cascadia/TerminalSettingsModel/Resources/en-US/Resources.resw
+++ b/src/cascadia/TerminalSettingsModel/Resources/en-US/Resources.resw
@@ -675,6 +675,9 @@
   <data name="CloseOtherPanesCommandKey" xml:space="preserve">
     <value>Close all other panes</value>
   </data>
+  <data name="RestartConnectionKey" xml:space="preserve">
+    <value>Restart connection</value>
+  </data>
   <data name="SelectOutputNextCommandKey" xml:space="preserve">
     <value>Select next command output</value>
   </data>
diff --git a/src/cascadia/TerminalSettingsModel/defaults.json b/src/cascadia/TerminalSettingsModel/defaults.json
index c57f6320c6c..daf9827edf3 100644
--- a/src/cascadia/TerminalSettingsModel/defaults.json
+++ b/src/cascadia/TerminalSettingsModel/defaults.json
@@ -449,6 +449,7 @@
         { "command": { "action": "movePane", "index": 6 } },
         { "command": { "action": "movePane", "index": 7 } },
         { "command": { "action": "movePane", "index": 8 } },
+        { "command": "restartConnection" },
 
         // Clipboard Integration
         { "command": { "action": "copy", "singleLine": false }, "keys": "ctrl+shift+c" },


Test patch: