-
Notifications
You must be signed in to change notification settings - Fork 8.4k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Allow exporting terminal buffer into file via tab context menu #11062
Changes from all commits
6351807
136ca87
b64b840
f49c07b
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -28,6 +28,9 @@ using namespace winrt::Windows::UI::Core; | |
using namespace winrt::Windows::System; | ||
using namespace winrt::Windows::ApplicationModel::DataTransfer; | ||
using namespace winrt::Windows::UI::Text; | ||
using namespace winrt::Windows::Storage; | ||
using namespace winrt::Windows::Storage::Pickers; | ||
using namespace winrt::Windows::Storage::Provider; | ||
using namespace winrt::Microsoft::Terminal; | ||
using namespace winrt::Microsoft::Terminal::Control; | ||
using namespace winrt::Microsoft::Terminal::TerminalConnection; | ||
|
@@ -171,6 +174,16 @@ namespace winrt::TerminalApp::implementation | |
} | ||
}); | ||
|
||
newTabImpl->ExportTabRequested([weakTab, weakThis{ get_weak() }]() { | ||
auto page{ weakThis.get() }; | ||
auto tab{ weakTab.get() }; | ||
|
||
if (page && tab) | ||
{ | ||
page->_ExportTab(*tab); | ||
} | ||
}); | ||
|
||
auto tabViewItem = newTabImpl->TabViewItem(); | ||
_tabView.TabItems().Append(tabViewItem); | ||
|
||
|
@@ -391,6 +404,45 @@ namespace winrt::TerminalApp::implementation | |
CATCH_LOG(); | ||
} | ||
|
||
// Method Description: | ||
// - Exports the content of the Terminal Buffer inside the tab | ||
// Arguments: | ||
// - tab: tab to export | ||
winrt::fire_and_forget TerminalPage::_ExportTab(const TerminalTab& tab) | ||
{ | ||
try | ||
{ | ||
if (const auto control{ tab.GetActiveTerminalControl() }) | ||
{ | ||
const FileSavePicker savePicker; | ||
savePicker.as<IInitializeWithWindow>()->Initialize(*_hostingHwnd); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Okay so just to be sure, this will work when the Terminal is elevated (run as admin), right? I want to make sure we don't run into the same issue that forced #9760 There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I do believe that it will crash. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It is pickers, of all sorts, through the W.S API that is broken, not any specific individual use. We may try/catch this one, but... the best we can do is simply not pop up a dialog when Admin. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Frick. I'll stick that on #9700 |
||
savePicker.SuggestedStartLocation(PickerLocationId::Downloads); | ||
const auto fileChoices = single_threaded_vector<hstring>({ L".txt" }); | ||
savePicker.FileTypeChoices().Insert(RS_(L"PlainText"), fileChoices); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Wait should "Plain Text" be localizable? I guess it should be, huh. |
||
savePicker.SuggestedFileName(control.Title()); | ||
|
||
const StorageFile file = co_await savePicker.PickSaveFileAsync(); | ||
if (file != nullptr) | ||
{ | ||
const auto buffer = control.ReadEntireBuffer(); | ||
CachedFileManager::DeferUpdates(file); | ||
co_await FileIO::WriteTextAsync(file, buffer); | ||
const auto status = co_await CachedFileManager::CompleteUpdatesAsync(file); | ||
switch (status) | ||
{ | ||
case FileUpdateStatus::Complete: | ||
case FileUpdateStatus::CompleteAndRenamed: | ||
_ShowControlNoticeDialog(RS_(L"NoticeInfo"), RS_(L"ExportSuccess")); | ||
break; | ||
default: | ||
_ShowControlNoticeDialog(RS_(L"NoticeError"), RS_(L"ExportFailure")); | ||
} | ||
} | ||
} | ||
} | ||
CATCH_LOG(); | ||
} | ||
|
||
// Method Description: | ||
// - Removes the tab (both TerminalControl and XAML) after prompting for approval | ||
// Arguments: | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -1211,13 +1211,31 @@ namespace winrt::TerminalApp::implementation | |
splitTabMenuItem.Icon(splitTabSymbol); | ||
} | ||
|
||
Controls::MenuFlyoutItem exportTabMenuItem; | ||
{ | ||
// "Split Tab" | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. nit: says "split" 😁 |
||
Controls::FontIcon exportTabSymbol; | ||
exportTabSymbol.FontFamily(Media::FontFamily{ L"Segoe MDL2 Assets" }); | ||
exportTabSymbol.Glyph(L"\xE74E"); // Save | ||
|
||
exportTabMenuItem.Click([weakThis](auto&&, auto&&) { | ||
if (auto tab{ weakThis.get() }) | ||
{ | ||
tab->_ExportTabRequestedHandlers(); | ||
} | ||
}); | ||
exportTabMenuItem.Text(RS_(L"ExportTabText")); | ||
exportTabMenuItem.Icon(exportTabSymbol); | ||
} | ||
|
||
// Build the menu | ||
Controls::MenuFlyout contextMenuFlyout; | ||
Controls::MenuFlyoutSeparator menuSeparator; | ||
contextMenuFlyout.Items().Append(chooseColorMenuItem); | ||
contextMenuFlyout.Items().Append(renameTabMenuItem); | ||
contextMenuFlyout.Items().Append(duplicateTabMenuItem); | ||
contextMenuFlyout.Items().Append(splitTabMenuItem); | ||
contextMenuFlyout.Items().Append(exportTabMenuItem); | ||
contextMenuFlyout.Items().Append(menuSeparator); | ||
|
||
// GH#5750 - When the context menu is dismissed with ESC, toss the focus | ||
|
@@ -1592,4 +1610,5 @@ namespace winrt::TerminalApp::implementation | |
DEFINE_EVENT(TerminalTab, TabRaiseVisualBell, _TabRaiseVisualBellHandlers, winrt::delegate<>); | ||
DEFINE_EVENT(TerminalTab, DuplicateRequested, _DuplicateRequestedHandlers, winrt::delegate<>); | ||
DEFINE_EVENT(TerminalTab, SplitTabRequested, _SplitTabRequestedHandlers, winrt::delegate<>); | ||
DEFINE_EVENT(TerminalTab, ExportTabRequested, _ExportTabRequestedHandlers, winrt::delegate<>); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
an aside: we may want to (in a future PR) turn this into an action, that could let the user export the pane to a file from the command palette too, not just the context menu. But now I'm thinking of all the other kinds of actions we could have for this feature...