diff --git a/src/cascadia/TerminalSettingsEditor/ActionsViewModel.cpp b/src/cascadia/TerminalSettingsEditor/ActionsViewModel.cpp index 26cc67547c..3bfbd6b92a 100644 --- a/src/cascadia/TerminalSettingsEditor/ActionsViewModel.cpp +++ b/src/cascadia/TerminalSettingsEditor/ActionsViewModel.cpp @@ -51,7 +51,7 @@ inline const std::set()); \ @@ -69,7 +69,7 @@ inline const std::set()); \ @@ -116,7 +116,7 @@ inline const std::set()); \ _FlagList = winrt::single_threaded_observable_vector(std::move(flagList)); \ - _NotifyChanges(L"FlagList", L"Value"); + _NotifyChanges(L"FlagList"); #define INITIALIZE_NULLABLE_FLAG_LIST_AND_VALUE(enumMappingsName, enumType, resourceSectionAndType, resourceProperty) \ std::vector flagList; \ @@ -189,7 +189,7 @@ inline const std::set(std::move(flagList)); \ - _NotifyChanges(L"FlagList", L"Value"); + _NotifyChanges(L"FlagList"); namespace winrt::Microsoft::Terminal::Settings::Editor::implementation { @@ -307,10 +307,7 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation const auto shortcutActionString = _AvailableActionsAndNamesMap.Lookup(_command.ActionAndArgs().Action()); ProposedShortcutAction(winrt::box_value(shortcutActionString)); - const auto actionArgsVM = make_self(_command.ActionAndArgs()); - _RegisterActionArgsVMEvents(*actionArgsVM); - actionArgsVM->Initialize(); - ActionArgsVM(*actionArgsVM); + _CreateAndInitializeActionArgsVMHelper(); // Add a property changed handler to our own property changed event. // This allows us to create a new ActionArgsVM when the shortcut action changes @@ -327,14 +324,16 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation // there are some other cases as well Model::ActionAndArgs newActionAndArgs{ actionEnum, emptyArgs }; _command.ActionAndArgs(newActionAndArgs); - const auto actionArgsVM = make_self(newActionAndArgs); - _RegisterActionArgsVMEvents(*actionArgsVM); - actionArgsVM->Initialize(); - ActionArgsVM(*actionArgsVM); if (_IsNewCommand) { _command.GenerateID(); } + else if (!IsUserAction()) + { + _ReplaceCommandWithUserCopy(); + return; + } + _CreateAndInitializeActionArgsVMHelper(); } }); } @@ -440,6 +439,35 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation _command.GenerateID(); }); } + else if (!IsUserAction()) + { + actionArgsVM.WrapperValueChanged([this](const IInspectable& /*sender*/, const IInspectable& /*args*/) { + _ReplaceCommandWithUserCopy(); + }); + } + } + + void CommandViewModel::_ReplaceCommandWithUserCopy() + { + // the user is attempting to edit an in-box action + // to handle this, we create a new command with the new values that has the same ID as the in-box action + // swap out our underlying command with the copy, tell the ActionsVM that the copy needs to be added to the action map + if (const auto actionsPageVM{ _actionsPageVM.get() }) + { + const auto newCmd = Model::Command::CopyAsUserCommand(_command); + _command = newCmd; + actionsPageVM.AttemptAddCopiedCommand(_command); + _CreateAndInitializeActionArgsVMHelper(); + } + } + + void CommandViewModel::_CreateAndInitializeActionArgsVMHelper() + { + const auto actionArgsVM = make_self(_command.ActionAndArgs()); + _RegisterActionArgsVMEvents(*actionArgsVM); + actionArgsVM->Initialize(); + ActionArgsVM(*actionArgsVM); + _NotifyChanges(L"DisplayName"); } ArgWrapper::ArgWrapper(const winrt::hstring& name, const winrt::hstring& type, const bool required, const Windows::Foundation::IInspectable& value) : @@ -625,27 +653,40 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation void ArgWrapper::StringBindBack(const winrt::hstring& newValue) { - Value(box_value(newValue)); + if (UnboxString(_Value) != newValue) + { + Value(box_value(newValue)); + } } void ArgWrapper::GuidBindBack(const winrt::hstring& newValue) { - // todo: probably need some validation? - Value(box_value(winrt::guid{ newValue })); + if (UnboxGuid(_Value) != newValue) + { + // todo: probably need some validation? + Value(box_value(winrt::guid{ newValue })); + } } void ArgWrapper::Int32BindBack(const double newValue) { - Value(box_value(static_cast(newValue))); + if (UnboxInt32(_Value) != newValue) + { + Value(box_value(static_cast(newValue))); + } } void ArgWrapper::Int32OptionalBindBack(const double newValue) { if (!isnan(newValue)) { - Value(box_value(static_cast(newValue))); + const auto currentValue = UnboxInt32Optional(_Value); + if (isnan(currentValue) || static_cast(currentValue) != static_cast(newValue)) + { + Value(box_value(static_cast(newValue))); + } } - else + else if (!_Value) { Value(nullptr); } @@ -653,16 +694,23 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation void ArgWrapper::UInt32BindBack(const double newValue) { - Value(box_value(static_cast(newValue))); + if (UnboxUInt32(_Value) != newValue) + { + Value(box_value(static_cast(newValue))); + } } void ArgWrapper::UInt32OptionalBindBack(const double newValue) { if (!isnan(newValue)) { - Value(box_value(static_cast(newValue))); + const auto currentValue = UnboxUInt32Optional(_Value); + if (isnan(currentValue) || static_cast(currentValue) != static_cast(newValue)) + { + Value(box_value(static_cast(newValue))); + } } - else + else if (!_Value) { Value(nullptr); } @@ -670,21 +718,31 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation void ArgWrapper::UInt64BindBack(const double newValue) { - Value(box_value(static_cast(newValue))); + if (UnboxUInt64(_Value) != newValue) + { + Value(box_value(static_cast(newValue))); + } } void ArgWrapper::FloatBindBack(const double newValue) { - Value(box_value(static_cast(newValue))); + if (UnboxFloat(_Value) != newValue) + { + Value(box_value(static_cast(newValue))); + } } - void ArgWrapper::BoolBindBack(const Windows::Foundation::IReference newValue) + void ArgWrapper::BoolOptionalBindBack(const Windows::Foundation::IReference newValue) { if (newValue) { - Value(box_value(newValue)); + const auto currentValue = UnboxBoolOptional(_Value); + if (!currentValue || currentValue.Value() != newValue.Value()) + { + Value(box_value(newValue)); + } } - else + else if (_Value) { Value(nullptr); } @@ -694,9 +752,13 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation { if (newValue) { - Value(box_value(newValue)); + const auto currentValue = UnboxTerminalCoreColorOptional(_Value); + if (!currentValue || currentValue.Value() != newValue.Value()) + { + Value(box_value(newValue)); + } } - else + else if (_Value) { Value(nullptr); } @@ -726,7 +788,7 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation } Value(box_value(Windows::Foundation::IReference{ winuiColor })); } - else + else if (_Value) { Value(nullptr); } @@ -1097,6 +1159,14 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation _Settings.ActionMap().AddKeyBinding(keys, cmdID); } + void ActionsViewModel::AttemptAddCopiedCommand(const Model::Command& newCommand) + { + // The command VM calls this when the user has edited an in-box action + // newCommand is a copy of the in-box action that was edited, but with OriginTag::User + // add it to the action map + _Settings.ActionMap().AddAction(newCommand, nullptr); + } + void ActionsViewModel::_KeyBindingViewModelPropertyChangedHandler(const IInspectable& sender, const Windows::UI::Xaml::Data::PropertyChangedEventArgs& args) { const auto senderVM{ sender.as() }; diff --git a/src/cascadia/TerminalSettingsEditor/ActionsViewModel.h b/src/cascadia/TerminalSettingsEditor/ActionsViewModel.h index d08fccc5db..63833e4c7e 100644 --- a/src/cascadia/TerminalSettingsEditor/ActionsViewModel.h +++ b/src/cascadia/TerminalSettingsEditor/ActionsViewModel.h @@ -163,6 +163,8 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation weak_ref _actionsPageVM{ nullptr }; void _RegisterKeyChordVMEvents(Editor::KeyChordViewModel kcVM); void _RegisterActionArgsVMEvents(Editor::ActionArgsViewModel actionArgsVM); + void _ReplaceCommandWithUserCopy(); + void _CreateAndInitializeActionArgsVMHelper(); Windows::Foundation::Collections::IMap _AvailableActionsAndNamesMap; std::unordered_map _NameToActionMap; }; @@ -205,7 +207,7 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation void UInt32OptionalBindBack(const double newValue); void UInt64BindBack(const double newValue); void FloatBindBack(const double newValue); - void BoolBindBack(const Windows::Foundation::IReference newValue); + void BoolOptionalBindBack(const Windows::Foundation::IReference newValue); void TerminalCoreColorBindBack(const winrt::Windows::Foundation::IReference newValue); void WindowsUIColorBindBack(const winrt::Windows::Foundation::IReference newValue); @@ -284,6 +286,7 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation void AttemptModifyKeyChord(const Editor::KeyChordViewModel& senderVM, const Editor::ModifyKeyChordEventArgs& args); void AttemptDeleteKeyChord(const Control::KeyChord& keys); void AttemptAddKeyChord(const Control::KeyChord& keys, const winrt::hstring& cmdID); + void AttemptAddCopiedCommand(const Model::Command& newCommand); til::typed_event FocusContainer; til::typed_event UpdateBackground; diff --git a/src/cascadia/TerminalSettingsEditor/ActionsViewModel.idl b/src/cascadia/TerminalSettingsEditor/ActionsViewModel.idl index 1228faf30c..3d64275663 100644 --- a/src/cascadia/TerminalSettingsEditor/ActionsViewModel.idl +++ b/src/cascadia/TerminalSettingsEditor/ActionsViewModel.idl @@ -61,7 +61,6 @@ namespace Microsoft.Terminal.Settings.Editor String Name; String ID; Boolean IsUserAction { get; }; - // icon // keybindings IObservableVector KeyChordViewModelList { get; }; // action args @@ -115,7 +114,7 @@ namespace Microsoft.Terminal.Settings.Editor void UInt32OptionalBindBack(Double newValue); void UInt64BindBack(Double newValue); void FloatBindBack(Double newValue); - void BoolBindBack(Windows.Foundation.IReference newValue); + void BoolOptionalBindBack(Windows.Foundation.IReference newValue); void TerminalCoreColorBindBack(Windows.Foundation.IReference newValue); void WindowsUIColorBindBack(Windows.Foundation.IReference newValue); @@ -173,6 +172,7 @@ namespace Microsoft.Terminal.Settings.Editor void AttemptAddKeyChord(Microsoft.Terminal.Control.KeyChord keys, String cmdID); void AttemptModifyKeyChord(KeyChordViewModel senderVM, ModifyKeyChordEventArgs args); void AttemptDeleteKeyChord(Microsoft.Terminal.Control.KeyChord keys); + void AttemptAddCopiedCommand(Microsoft.Terminal.Settings.Model.Command newCommand); IObservableVector CommandList { get; }; void CmdListItemClicked(IInspectable sender, Windows.UI.Xaml.Controls.ItemClickEventArgs args); diff --git a/src/cascadia/TerminalSettingsEditor/ArgsTemplateSelectors.cpp b/src/cascadia/TerminalSettingsEditor/ArgsTemplateSelectors.cpp index bf8d8d41ed..aab56a997e 100644 --- a/src/cascadia/TerminalSettingsEditor/ArgsTemplateSelectors.cpp +++ b/src/cascadia/TerminalSettingsEditor/ArgsTemplateSelectors.cpp @@ -53,7 +53,6 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation else if (argType == L"bool" || argType == L"Windows::Foundation::IReference") { - // we don't have any bool args that are required, so just use the optional template for all of them return BoolOptionalTemplate(); } else if (argType == L"Windows::Foundation::IReference") diff --git a/src/cascadia/TerminalSettingsEditor/EditAction.xaml b/src/cascadia/TerminalSettingsEditor/EditAction.xaml index e958cfb426..069f5b3af8 100644 --- a/src/cascadia/TerminalSettingsEditor/EditAction.xaml +++ b/src/cascadia/TerminalSettingsEditor/EditAction.xaml @@ -409,7 +409,7 @@ - @@ -556,9 +556,8 @@ VerticalAlignment="Center" Grid.Column="0" Grid.Row="0"/> - , TabColor, "tabColor", false, nullptr) \ X(Windows::Foundation::IReference, ProfileIndex, "index", false, nullptr) \ X(winrt::hstring, Profile, "profile", false, L"") \ - X(bool, AppendCommandLine, "appendCommandLine", false, false) \ X(Windows::Foundation::IReference, SuppressApplicationTitle, "suppressApplicationTitle", false, nullptr) \ X(winrt::hstring, ColorScheme, "colorScheme", args->SchemeName().empty(), L"") \ X(Windows::Foundation::IReference, Elevate, "elevate", false, nullptr) \ @@ -381,9 +380,11 @@ namespace winrt::Microsoft::Terminal::Settings::Model::implementation PARTIAL_ACTION_ARG_BODY(NewTerminalArgs, NEW_TERMINAL_ARGS); ACTION_ARG(winrt::hstring, Type, L""); ACTION_ARG(winrt::guid, SessionId, winrt::guid{}); + ACTION_ARG(bool, AppendCommandLine, false); ACTION_ARG(uint64_t, ContentId); static constexpr std::string_view SessionIdKey{ "sessionId" }; + static constexpr std::string_view AppendCommandLineKey{ "appendCommandLine" }; static constexpr std::string_view ContentKey{ "__content" }; public: diff --git a/src/cascadia/TerminalSettingsModel/Command.cpp b/src/cascadia/TerminalSettingsModel/Command.cpp index de0f195f78..476e95e484 100644 --- a/src/cascadia/TerminalSettingsModel/Command.cpp +++ b/src/cascadia/TerminalSettingsModel/Command.cpp @@ -35,6 +35,14 @@ namespace winrt::Microsoft::Terminal::Settings::Model::implementation return *newCmd; } + Model::Command Command::CopyAsUserCommand(Model::Command originalCmd) + { + auto command{ winrt::get_self(originalCmd) }; + auto copy{ command->Copy() }; + copy->_Origin = OriginTag::User; + return *copy; + } + com_ptr Command::Copy() const { auto command{ winrt::make_self() }; diff --git a/src/cascadia/TerminalSettingsModel/Command.h b/src/cascadia/TerminalSettingsModel/Command.h index 7dae7f2aec..e4f98b8bb7 100644 --- a/src/cascadia/TerminalSettingsModel/Command.h +++ b/src/cascadia/TerminalSettingsModel/Command.h @@ -46,6 +46,7 @@ namespace winrt::Microsoft::Terminal::Settings::Model::implementation { Command(); static Model::Command NewUserCommand(); + static Model::Command CopyAsUserCommand(Model::Command originalCmd); com_ptr Copy() const; static winrt::com_ptr FromJson(const Json::Value& json, diff --git a/src/cascadia/TerminalSettingsModel/Command.idl b/src/cascadia/TerminalSettingsModel/Command.idl index 57c8faa7ae..310b040205 100644 --- a/src/cascadia/TerminalSettingsModel/Command.idl +++ b/src/cascadia/TerminalSettingsModel/Command.idl @@ -36,6 +36,7 @@ namespace Microsoft.Terminal.Settings.Model { Command(); static Command NewUserCommand(); + static Command CopyAsUserCommand(Command originalCmd); String Name; Boolean HasName();