Skip to content

Commit

Permalink
Add an exportBuffer action (#12097)
Browse files Browse the repository at this point in the history
This adds an action for the context menu entry we added in #11062. That PR added support for exporting the buffer, exclusively through the tab item's context menu. This adds an action that can additionally be bound, which also can export the buffer to a file. This action accepts a `path` param. If empty/ommitted, then the Terminal will prompt for the file to export the buffer to. 

* Does a part of #9700
* Spec in #11090, but I doubt this is contentious
* [x] This will satisfy #12052
* [x] I work here
* [x] docs added: MicrosoftDocs/terminal#479
  • Loading branch information
zadjii-msft authored Jan 12, 2022
1 parent bc97af7 commit 862d8ed
Show file tree
Hide file tree
Showing 11 changed files with 161 additions and 22 deletions.
58 changes: 58 additions & 0 deletions doc/cascadia/profiles.schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -281,6 +281,7 @@
"ShortcutActionName": {
"enum": [
"adjustFontSize",
"clearBuffer",
"closeOtherTabs",
"closePane",
"closeTab",
Expand All @@ -289,6 +290,7 @@
"commandPalette",
"copy",
"duplicateTab",
"exportBuffer",
"find",
"findMatch",
"focusPane",
Expand Down Expand Up @@ -434,6 +436,14 @@
],
"type": "string"
},
"ClearBufferType": {
"enum": [
"all",
"screen",
"scrollback"
],
"type": "string"
},
"NewTerminalArgs": {
"properties": {
"commandline": {
Expand Down Expand Up @@ -1266,6 +1276,48 @@
}
]
},
"ClearBufferAction": {
"description": "Arguments corresponding to a clearBuffer Action",
"allOf": [
{
"$ref": "#/$defs/ShortcutAction"
},
{
"properties": {
"action": {
"type": "string",
"const": "clearBuffer"
},
"clear": {
"$ref": "#/$defs/ClearBufferType",
"default": "all",
"description": "What to clear. Accepts one of `screen`, `scrollback` or `all` (for both)."
}
}
}
]
},
"ExportBufferAction": {
"description": "Arguments corresponding to a exportBuffer Action",
"allOf": [
{
"$ref": "#/$defs/ShortcutAction"
},
{
"properties": {
"action": {
"type": "string",
"const": "exportBuffer"
},
"path": {
"type": "string",
"default": "",
"description": "The path to export the text buffer to. If left blank, the Terminal will open a file picker to choose the path."
}
}
}
]
},
"GlobalSummonAction": {
"description": "This is a special action that works globally in the OS, rather than only in the context of the terminal window. When pressed, this action will summon the terminal window.",
"allOf": [
Expand Down Expand Up @@ -1429,6 +1481,12 @@
{
"$ref": "#/$defs/FocusPaneAction"
},
{
"$ref": "#/$defs/ExportBufferAction"
},
{
"$ref": "#/$defs/ClearBufferAction"
},
{
"$ref": "#/$defs/GlobalSummonAction"
},
Expand Down
21 changes: 21 additions & 0 deletions src/cascadia/TerminalApp/AppActionHandlers.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -906,6 +906,27 @@ namespace winrt::TerminalApp::implementation
args.Handled(true);
}

void TerminalPage::_HandleExportBuffer(const IInspectable& /*sender*/,
const ActionEventArgs& args)
{
if (const auto activeTab{ _GetFocusedTabImpl() })
{
if (args)
{
if (const auto& realArgs = args.ActionArgs().try_as<ExportBufferArgs>())
{
_ExportTab(*activeTab, realArgs.Path());
args.Handled(true);
return;
}
}

// If we didn't have args, or the args weren't ExportBufferArgs (somehow)
_ExportTab(*activeTab, L"");
args.Handled(true);
}
}

void TerminalPage::_HandleClearBuffer(const IInspectable& /*sender*/,
const ActionEventArgs& args)
{
Expand Down
57 changes: 36 additions & 21 deletions src/cascadia/TerminalApp/TabManagement.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -194,7 +194,9 @@ namespace winrt::TerminalApp::implementation

if (page && tab)
{
page->_ExportTab(*tab);
// Passing null args to the ExportBuffer handler will default it
// to prompting for the path
page->_HandleExportBuffer(nullptr, nullptr);
}
});

Expand Down Expand Up @@ -359,7 +361,7 @@ namespace winrt::TerminalApp::implementation
// - Exports the content of the Terminal Buffer inside the tab
// Arguments:
// - tab: tab to export
winrt::fire_and_forget TerminalPage::_ExportTab(const TerminalTab& tab)
winrt::fire_and_forget TerminalPage::_ExportTab(const TerminalTab& tab, winrt::hstring filepath)
{
// This will be used to set up the file picker "filter", to select .txt
// files by default.
Expand All @@ -376,25 +378,38 @@ namespace winrt::TerminalApp::implementation
{
if (const auto control{ tab.GetActiveTerminalControl() })
{
// GH#11356 - we can't use the UWP apis for writing the file,
// because they don't work elevated (shocker) So just use the
// shell32 file picker manually.
auto path = co_await SaveFilePicker(*_hostingHwnd, [control](auto&& dialog) {
THROW_IF_FAILED(dialog->SetClientGuid(clientGuidExportFile));
try
{
// Default to the Downloads folder
auto folderShellItem{ winrt::capture<IShellItem>(&SHGetKnownFolderItem, FOLDERID_Downloads, KF_FLAG_DEFAULT, nullptr) };
dialog->SetDefaultFolder(folderShellItem.get());
}
CATCH_LOG(); // non-fatal
THROW_IF_FAILED(dialog->SetFileTypes(ARRAYSIZE(supportedFileTypes), supportedFileTypes));
THROW_IF_FAILED(dialog->SetFileTypeIndex(1)); // the array is 1-indexed
THROW_IF_FAILED(dialog->SetDefaultExtension(L"txt"));

// Default to using the tab title as the file name
THROW_IF_FAILED(dialog->SetFileName((control.Title() + L".txt").c_str()));
});
auto path = filepath;

if (path.empty())
{
// GH#11356 - we can't use the UWP apis for writing the file,
// because they don't work elevated (shocker) So just use the
// shell32 file picker manually.
path = co_await SaveFilePicker(*_hostingHwnd, [control](auto&& dialog) {
THROW_IF_FAILED(dialog->SetClientGuid(clientGuidExportFile));
try
{
// Default to the Downloads folder
auto folderShellItem{ winrt::capture<IShellItem>(&SHGetKnownFolderItem, FOLDERID_Downloads, KF_FLAG_DEFAULT, nullptr) };
dialog->SetDefaultFolder(folderShellItem.get());
}
CATCH_LOG(); // non-fatal
THROW_IF_FAILED(dialog->SetFileTypes(ARRAYSIZE(supportedFileTypes), supportedFileTypes));
THROW_IF_FAILED(dialog->SetFileTypeIndex(1)); // the array is 1-indexed
THROW_IF_FAILED(dialog->SetDefaultExtension(L"txt"));

// Default to using the tab title as the file name
THROW_IF_FAILED(dialog->SetFileName((control.Title() + L".txt").c_str()));
});
}
else
{
// The file picker isn't going to give us paths with
// environment variables, but the user might have set one in
// the settings. Expand those here.

path = { wil::ExpandEnvironmentStringsW<std::wstring>(path.c_str()) };
}

if (!path.empty())
{
Expand Down
2 changes: 1 addition & 1 deletion src/cascadia/TerminalApp/TerminalPage.h
Original file line number Diff line number Diff line change
Expand Up @@ -256,7 +256,7 @@ namespace winrt::TerminalApp::implementation
void _DuplicateTab(const TerminalTab& tab);

void _SplitTab(TerminalTab& tab);
winrt::fire_and_forget _ExportTab(const TerminalTab& tab);
winrt::fire_and_forget _ExportTab(const TerminalTab& tab, winrt::hstring filepath);

winrt::Windows::Foundation::IAsyncAction _HandleCloseTabRequested(winrt::TerminalApp::TabBase tab);
void _CloseTabAtIndex(uint32_t index);
Expand Down
2 changes: 2 additions & 0 deletions src/cascadia/TerminalSettingsModel/ActionAndArgs.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,7 @@ static constexpr std::string_view GlobalSummonKey{ "globalSummon" };
static constexpr std::string_view QuakeModeKey{ "quakeMode" };
static constexpr std::string_view FocusPaneKey{ "focusPane" };
static constexpr std::string_view OpenSystemMenuKey{ "openSystemMenu" };
static constexpr std::string_view ExportBufferKey{ "exportBuffer" };
static constexpr std::string_view ClearBufferKey{ "clearBuffer" };
static constexpr std::string_view MultipleActionsKey{ "multipleActions" };
static constexpr std::string_view QuitKey{ "quit" };
Expand Down Expand Up @@ -378,6 +379,7 @@ namespace winrt::Microsoft::Terminal::Settings::Model::implementation
{ ShortcutAction::QuakeMode, RS_(L"QuakeModeCommandKey") },
{ ShortcutAction::FocusPane, L"" }, // Intentionally omitted, must be generated by GenerateName
{ ShortcutAction::OpenSystemMenu, RS_(L"OpenSystemMenuCommandKey") },
{ ShortcutAction::ExportBuffer, L"" }, // Intentionally omitted, must be generated by GenerateName
{ ShortcutAction::ClearBuffer, L"" }, // Intentionally omitted, must be generated by GenerateName
{ ShortcutAction::MultipleActions, L"" }, // Intentionally omitted, must be generated by GenerateName
{ ShortcutAction::Quit, RS_(L"QuitCommandKey") },
Expand Down
19 changes: 19 additions & 0 deletions src/cascadia/TerminalSettingsModel/ActionArgs.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@
#include "RenameWindowArgs.g.cpp"
#include "GlobalSummonArgs.g.cpp"
#include "FocusPaneArgs.g.cpp"
#include "ExportBufferArgs.g.cpp"
#include "ClearBufferArgs.g.cpp"
#include "MultipleActionsArgs.g.cpp"

Expand Down Expand Up @@ -727,6 +728,24 @@ namespace winrt::Microsoft::Terminal::Settings::Model::implementation
Id())
};
}

winrt::hstring ExportBufferArgs::GenerateName() const
{
if (!Path().empty())
{
// "Export text to {path}"
return winrt::hstring{
fmt::format(std::wstring_view(RS_(L"ExportBufferToPathCommandKey")),
Path())
};
}
else
{
// "Export text"
return RS_(L"ExportBufferCommandKey");
}
}

winrt::hstring ClearBufferArgs::GenerateName() const
{
// "Clear Buffer"
Expand Down
8 changes: 8 additions & 0 deletions src/cascadia/TerminalSettingsModel/ActionArgs.h
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@
#include "RenameWindowArgs.g.h"
#include "GlobalSummonArgs.g.h"
#include "FocusPaneArgs.g.h"
#include "ExportBufferArgs.g.h"
#include "ClearBufferArgs.g.h"
#include "MultipleActionsArgs.g.h"

Expand Down Expand Up @@ -210,6 +211,10 @@ private:
#define FOCUS_PANE_ARGS(X) \
X(uint32_t, Id, "id", false, 0u)

////////////////////////////////////////////////////////////////////////////////
#define EXPORT_BUFFER_ARGS(X) \
X(winrt::hstring, Path, "path", false, L"")

////////////////////////////////////////////////////////////////////////////////
#define CLEAR_BUFFER_ARGS(X) \
X(winrt::Microsoft::Terminal::Control::ClearBufferType, Clear, "clear", false, winrt::Microsoft::Terminal::Control::ClearBufferType::All)
Expand Down Expand Up @@ -631,6 +636,8 @@ namespace winrt::Microsoft::Terminal::Settings::Model::implementation

ACTION_ARGS_STRUCT(FocusPaneArgs, FOCUS_PANE_ARGS);

ACTION_ARGS_STRUCT(ExportBufferArgs, EXPORT_BUFFER_ARGS);

ACTION_ARGS_STRUCT(ClearBufferArgs, CLEAR_BUFFER_ARGS);

struct MultipleActionsArgs : public MultipleActionsArgsT<MultipleActionsArgs>
Expand Down Expand Up @@ -713,6 +720,7 @@ namespace winrt::Microsoft::Terminal::Settings::Model::factory_implementation
BASIC_FACTORY(FocusPaneArgs);
BASIC_FACTORY(PrevTabArgs);
BASIC_FACTORY(NextTabArgs);
BASIC_FACTORY(ExportBufferArgs);
BASIC_FACTORY(ClearBufferArgs);
BASIC_FACTORY(MultipleActionsArgs);
}
6 changes: 6 additions & 0 deletions src/cascadia/TerminalSettingsModel/ActionArgs.idl
Original file line number Diff line number Diff line change
Expand Up @@ -342,6 +342,12 @@ namespace Microsoft.Terminal.Settings.Model
UInt32 Id { get; };
};

[default_interface] runtimeclass ExportBufferArgs : IActionArgs
{
ExportBufferArgs(String path);
String Path { get; };
};

[default_interface] runtimeclass ClearBufferArgs : IActionArgs
{
ClearBufferArgs(Microsoft.Terminal.Control.ClearBufferType clear);
Expand Down
2 changes: 2 additions & 0 deletions src/cascadia/TerminalSettingsModel/AllShortcutActions.h
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,7 @@
ON_ALL_ACTIONS(QuakeMode) \
ON_ALL_ACTIONS(FocusPane) \
ON_ALL_ACTIONS(OpenSystemMenu) \
ON_ALL_ACTIONS(ExportBuffer) \
ON_ALL_ACTIONS(ClearBuffer) \
ON_ALL_ACTIONS(MultipleActions) \
ON_ALL_ACTIONS(Quit) \
Expand Down Expand Up @@ -121,5 +122,6 @@
ON_ALL_ACTIONS_WITH_ARGS(SwitchToTab) \
ON_ALL_ACTIONS_WITH_ARGS(ToggleCommandPalette) \
ON_ALL_ACTIONS_WITH_ARGS(FocusPane) \
ON_ALL_ACTIONS_WITH_ARGS(ExportBuffer) \
ON_ALL_ACTIONS_WITH_ARGS(ClearBuffer) \
ON_ALL_ACTIONS_WITH_ARGS(MultipleActions)
Original file line number Diff line number Diff line change
Expand Up @@ -473,6 +473,13 @@
<value>Focus pane {0}</value>
<comment>{0} will be replaced with a user-specified number</comment>
</data>
<data name="ExportBufferToPathCommandKey" xml:space="preserve">
<value>Export text to {0}</value>
<comment>{0} will be replaced with a user-specified file path</comment>
</data>
<data name="ExportBufferCommandKey" xml:space="preserve">
<value>Export text</value>
</data>
<data name="ClearAllCommandKey" xml:space="preserve">
<value>Clear buffer</value>
<comment>A command to clear the entirety of the Terminal output buffer</comment>
Expand Down
1 change: 1 addition & 0 deletions src/cascadia/TerminalSettingsModel/defaults.json
Original file line number Diff line number Diff line change
Expand Up @@ -393,6 +393,7 @@
{ "command": "scrollToTop", "keys": "ctrl+shift+home" },
{ "command": "scrollToBottom", "keys": "ctrl+shift+end" },
{ "command": { "action": "clearBuffer", "clear": "all" } },
{ "command": "exportBuffer" },

// Visual Adjustments
{ "command": { "action": "adjustFontSize", "delta": 1 }, "keys": "ctrl+plus" },
Expand Down

0 comments on commit 862d8ed

Please sign in to comment.