Teach CommandPalette to persist recent command lines (#11030)
Closes #11026
This commit is contained in:
parent
7423734a48
commit
7112f4e081
|
@ -36,7 +36,6 @@ namespace winrt::TerminalApp::implementation
|
|||
_allCommands = winrt::single_threaded_vector<winrt::TerminalApp::FilteredCommand>();
|
||||
_tabActions = winrt::single_threaded_vector<winrt::TerminalApp::FilteredCommand>();
|
||||
_mruTabActions = winrt::single_threaded_vector<winrt::TerminalApp::FilteredCommand>();
|
||||
_commandLineHistory = winrt::single_threaded_vector<winrt::TerminalApp::FilteredCommand>();
|
||||
|
||||
_switchToMode(CommandPaletteMode::ActionMode);
|
||||
|
||||
|
@ -587,7 +586,7 @@ namespace winrt::TerminalApp::implementation
|
|||
case CommandPaletteMode::TabSwitchMode:
|
||||
return _tabSwitcherMode == TabSwitcherMode::MostRecentlyUsed ? _mruTabActions : _tabActions;
|
||||
case CommandPaletteMode::CommandlineMode:
|
||||
return _commandLineHistory;
|
||||
return _loadRecentCommands();
|
||||
default:
|
||||
return _allCommands;
|
||||
}
|
||||
|
@ -720,14 +719,10 @@ namespace winrt::TerminalApp::implementation
|
|||
// - <none>
|
||||
void CommandPalette::_dispatchCommandline(winrt::TerminalApp::FilteredCommand const& command)
|
||||
{
|
||||
const auto filteredCommand = command ? command : _buildCommandLineCommand(_getTrimmedInput());
|
||||
const auto filteredCommand = command ? command : _buildCommandLineCommand(winrt::hstring(_getTrimmedInput()));
|
||||
if (filteredCommand.has_value())
|
||||
{
|
||||
if (_commandLineHistory.Size() == CommandLineHistoryLength)
|
||||
{
|
||||
_commandLineHistory.RemoveAtEnd();
|
||||
}
|
||||
_commandLineHistory.InsertAt(0, filteredCommand.value());
|
||||
_updateRecentCommands(filteredCommand.value().Item().Name());
|
||||
|
||||
TraceLoggingWrite(
|
||||
g_hTerminalAppProvider, // handle to TerminalApp tracelogging provider
|
||||
|
@ -744,15 +739,14 @@ namespace winrt::TerminalApp::implementation
|
|||
}
|
||||
}
|
||||
|
||||
std::optional<winrt::TerminalApp::FilteredCommand> CommandPalette::_buildCommandLineCommand(std::wstring const& commandLine)
|
||||
std::optional<TerminalApp::FilteredCommand> CommandPalette::_buildCommandLineCommand(const hstring& commandLine)
|
||||
{
|
||||
if (commandLine.empty())
|
||||
{
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
winrt::hstring cl{ commandLine };
|
||||
auto commandLinePaletteItem{ winrt::make<winrt::TerminalApp::implementation::CommandLinePaletteItem>(cl) };
|
||||
auto commandLinePaletteItem{ winrt::make<CommandLinePaletteItem>(commandLine) };
|
||||
return winrt::make<FilteredCommand>(commandLinePaletteItem);
|
||||
}
|
||||
|
||||
|
@ -1217,4 +1211,48 @@ namespace winrt::TerminalApp::implementation
|
|||
itemContainer.DataContext(args.Item());
|
||||
}
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
// - Reads the list of recent commands from the persistent application state
|
||||
// Return Value:
|
||||
// - The list of FilteredCommand representing the ones stored in the state
|
||||
IVector<TerminalApp::FilteredCommand> CommandPalette::_loadRecentCommands()
|
||||
{
|
||||
const auto recentCommands = ApplicationState::SharedInstance().RecentCommands();
|
||||
std::vector<TerminalApp::FilteredCommand> parsedCommands;
|
||||
parsedCommands.reserve(std::min(recentCommands.Size(), CommandLineHistoryLength));
|
||||
|
||||
for (const auto& c : recentCommands)
|
||||
{
|
||||
if (parsedCommands.size() >= CommandLineHistoryLength)
|
||||
{
|
||||
// Don't load more than CommandLineHistoryLength commands
|
||||
break;
|
||||
}
|
||||
|
||||
if (const auto parsedCommand = _buildCommandLineCommand(c))
|
||||
{
|
||||
parsedCommands.push_back(*parsedCommand);
|
||||
}
|
||||
}
|
||||
return single_threaded_vector(std::move(parsedCommands));
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
// - Update recent commands by putting the provided command as most recent.
|
||||
// Upon race condition might override an update made by another window.
|
||||
// Return Value:
|
||||
// - <none>
|
||||
void CommandPalette::_updateRecentCommands(const hstring& command)
|
||||
{
|
||||
const auto recentCommands = ApplicationState::SharedInstance().RecentCommands();
|
||||
const auto countToCopy = std::min(recentCommands.Size(), CommandLineHistoryLength - 1);
|
||||
std::vector<hstring> newRecentCommands{ countToCopy + 1 };
|
||||
til::at(newRecentCommands, 0) = command;
|
||||
if (countToCopy)
|
||||
{
|
||||
recentCommands.GetMany(0, { newRecentCommands.data() + 1, countToCopy });
|
||||
}
|
||||
ApplicationState::SharedInstance().RecentCommands(single_threaded_vector(std::move(newRecentCommands)));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -123,15 +123,16 @@ namespace winrt::TerminalApp::implementation
|
|||
void _dispatchCommand(winrt::TerminalApp::FilteredCommand const& command);
|
||||
void _dispatchCommandline(winrt::TerminalApp::FilteredCommand const& command);
|
||||
void _switchToTab(winrt::TerminalApp::FilteredCommand const& command);
|
||||
std::optional<winrt::TerminalApp::FilteredCommand> _buildCommandLineCommand(std::wstring const& commandLine);
|
||||
static std::optional<winrt::TerminalApp::FilteredCommand> _buildCommandLineCommand(const winrt::hstring& commandLine);
|
||||
|
||||
void _dismissPalette();
|
||||
|
||||
void _scrollToIndex(uint32_t index);
|
||||
uint32_t _getNumVisibleItems();
|
||||
|
||||
static constexpr int CommandLineHistoryLength = 10;
|
||||
Windows::Foundation::Collections::IVector<winrt::TerminalApp::FilteredCommand> _commandLineHistory{ nullptr };
|
||||
static constexpr uint32_t CommandLineHistoryLength = 20;
|
||||
static Windows::Foundation::Collections::IVector<winrt::TerminalApp::FilteredCommand> _loadRecentCommands();
|
||||
static void _updateRecentCommands(const winrt::hstring& command);
|
||||
::TerminalApp::AppCommandlineArgs _appArgs;
|
||||
|
||||
void _choosingItemContainer(Windows::UI::Xaml::Controls::ListViewBase const& sender, Windows::UI::Xaml::Controls::ChoosingItemContainerEventArgs const& args);
|
||||
|
|
|
@ -55,6 +55,48 @@ namespace Microsoft::Terminal::Settings::Model::JsonUtils
|
|||
return fmt::format("{}[]", ConversionTrait<GUID>{}.TypeDescription());
|
||||
}
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
struct ConversionTrait<winrt::Windows::Foundation::Collections::IVector<T>>
|
||||
{
|
||||
winrt::Windows::Foundation::Collections::IVector<T> FromJson(const Json::Value& json) const
|
||||
{
|
||||
ConversionTrait<T> trait;
|
||||
std::vector<T> val;
|
||||
val.reserve(json.size());
|
||||
|
||||
for (const auto& element : json)
|
||||
{
|
||||
val.push_back(trait.FromJson(element));
|
||||
}
|
||||
|
||||
return winrt::single_threaded_vector(move(val));
|
||||
}
|
||||
|
||||
bool CanConvert(const Json::Value& json) const
|
||||
{
|
||||
ConversionTrait<T> trait;
|
||||
return json.isArray() && std::all_of(json.begin(), json.end(), [trait](const auto& json) -> bool { return trait.CanConvert(json); });
|
||||
}
|
||||
|
||||
Json::Value ToJson(const winrt::Windows::Foundation::Collections::IVector<T>& val)
|
||||
{
|
||||
ConversionTrait<T> trait;
|
||||
Json::Value json{ Json::arrayValue };
|
||||
|
||||
for (const auto& key : val)
|
||||
{
|
||||
json.append(trait.ToJson(key));
|
||||
}
|
||||
|
||||
return json;
|
||||
}
|
||||
|
||||
std::string TypeDescription() const
|
||||
{
|
||||
return fmt::format("vector ({})", ConversionTrait<T>{}.TypeDescription());
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
using namespace ::Microsoft::Terminal::Settings::Model;
|
||||
|
|
|
@ -21,8 +21,9 @@ Abstract:
|
|||
// This macro generates all getters and setters for ApplicationState.
|
||||
// It provides X with the following arguments:
|
||||
// (type, function name, JSON key, ...variadic construction arguments)
|
||||
#define MTSM_APPLICATION_STATE_FIELDS(X) \
|
||||
X(std::unordered_set<winrt::guid>, GeneratedProfiles, "generatedProfiles")
|
||||
#define MTSM_APPLICATION_STATE_FIELDS(X) \
|
||||
X(std::unordered_set<winrt::guid>, GeneratedProfiles, "generatedProfiles") \
|
||||
X(Windows::Foundation::Collections::IVector<hstring>, RecentCommands, "recentCommands")
|
||||
|
||||
namespace winrt::Microsoft::Terminal::Settings::Model::implementation
|
||||
{
|
||||
|
|
|
@ -9,5 +9,7 @@ namespace Microsoft.Terminal.Settings.Model
|
|||
void Reload();
|
||||
|
||||
String FilePath { get; };
|
||||
|
||||
Windows.Foundation.Collections.IVector<String> RecentCommands { get; set; };
|
||||
}
|
||||
}
|
||||
|
|
|
@ -161,7 +161,7 @@ namespace Microsoft::Terminal::Settings::Model::JsonUtils
|
|||
return til::u8u16(Detail::GetStringView(json));
|
||||
}
|
||||
|
||||
bool CanConvert(const Json::Value& json)
|
||||
bool CanConvert(const Json::Value& json) const
|
||||
{
|
||||
return json.isString();
|
||||
}
|
||||
|
@ -252,7 +252,7 @@ namespace Microsoft::Terminal::Settings::Model::JsonUtils
|
|||
return til::u16u8(val);
|
||||
}
|
||||
|
||||
bool CanConvert(const Json::Value& json)
|
||||
bool CanConvert(const Json::Value& json) const
|
||||
{
|
||||
// hstring has a specific behavior for null, so it can convert it
|
||||
return ConversionTrait<std::wstring>::CanConvert(json) || json.isNull();
|
||||
|
|
Loading…
Reference in New Issue