Skip to content

Commit

Permalink
Add --pos and --size cmdline args (microsoft#13730)
Browse files Browse the repository at this point in the history
Adds `--pos`, and `--size` commandline arguments to `wt`.

Closes microsoft#4620
  • Loading branch information
ianjoneill committed Oct 7, 2022
1 parent 3517a6a commit 43dbbd5
Show file tree
Hide file tree
Showing 10 changed files with 151 additions and 48 deletions.
22 changes: 21 additions & 1 deletion src/cascadia/TerminalApp/AppCommandlineArgs.cpp
Expand Up @@ -4,6 +4,7 @@
#include "pch.h"
#include "AppCommandlineArgs.h"
#include "../types/inc/utils.hpp"
#include "TerminalSettingsModel/ModelSerializationHelpers.h"
#include <LibraryResources.h>

using namespace winrt::Microsoft::Terminal::Settings::Model;
Expand Down Expand Up @@ -183,6 +184,15 @@ void AppCommandlineArgs::_buildParser()
maximized->excludes(fullscreen);
focus->excludes(fullscreen);

auto positionCallback = [this](std::string string) {
_position = LaunchPositionFromString(string);
};
_app.add_option_function<std::string>("--pos", positionCallback, RS_A(L"CmdPositionDesc"));
auto sizeCallback = [this](std::string string) {
_size = SizeFromString(string);
};
_app.add_option_function<std::string>("--size", sizeCallback, RS_A(L"CmdSizeDesc"));

_app.add_option("-w,--window",
_windowTarget,
RS_A(L"CmdWindowTargetArgDesc"));
Expand Down Expand Up @@ -709,7 +719,7 @@ void AppCommandlineArgs::_resetStateToDefault()
// DON'T clear _launchMode here! This will get called once for every
// subcommand, so we don't want `wt -F new-tab ; split-pane` clearing out
// the "global" fullscreen flag (-F).
// Same with _windowTarget.
// Same with _windowTarget, _position and _size.
}

// Function Description:
Expand Down Expand Up @@ -936,6 +946,16 @@ std::optional<winrt::Microsoft::Terminal::Settings::Model::LaunchMode> AppComman
return _launchMode;
}

std::optional<winrt::Microsoft::Terminal::Settings::Model::LaunchPosition> AppCommandlineArgs::GetPosition() const noexcept
{
return _position;
}

std::optional<til::size> AppCommandlineArgs::GetSize() const noexcept
{
return _size;
}

// Method Description:
// - Attempts to parse an array of commandline args into a list of
// commands to execute, and then parses these commands. As commands are
Expand Down
4 changes: 4 additions & 0 deletions src/cascadia/TerminalApp/AppCommandlineArgs.h
Expand Up @@ -41,6 +41,8 @@ class TerminalApp::AppCommandlineArgs final

std::optional<uint32_t> GetPersistedLayoutIdx() const noexcept;
std::optional<winrt::Microsoft::Terminal::Settings::Model::LaunchMode> GetLaunchMode() const noexcept;
std::optional<winrt::Microsoft::Terminal::Settings::Model::LaunchPosition> GetPosition() const noexcept;
std::optional<til::size> GetSize() const noexcept;

int ParseArgs(const winrt::Microsoft::Terminal::Settings::Model::ExecuteCommandlineArgs& args);
void DisableHelpInExitMessage();
Expand Down Expand Up @@ -119,6 +121,8 @@ class TerminalApp::AppCommandlineArgs final

const Commandline* _currentCommandline{ nullptr };
std::optional<winrt::Microsoft::Terminal::Settings::Model::LaunchMode> _launchMode{ std::nullopt };
std::optional<winrt::Microsoft::Terminal::Settings::Model::LaunchPosition> _position{ std::nullopt };
std::optional<til::size> _size{ std::nullopt };
bool _isHandoffListener{ false };
std::vector<winrt::Microsoft::Terminal::Settings::Model::ActionAndArgs> _startupActions;
std::string _exitMessage;
Expand Down
15 changes: 13 additions & 2 deletions src/cascadia/TerminalApp/AppLogic.cpp
Expand Up @@ -633,12 +633,17 @@ namespace winrt::TerminalApp::implementation
}
}

if (proposedSize.Width == 0 && proposedSize.Height == 0)
if (_appArgs.GetSize().has_value() || (proposedSize.Width == 0 && proposedSize.Height == 0))
{
// Use the default profile to determine how big of a window we need.
const auto settings{ TerminalSettings::CreateWithNewTerminalArgs(_settings, nullptr, nullptr) };

proposedSize = TermControl::GetProposedDimensions(settings.DefaultSettings(), dpi);
const til::size emptySize{};
const auto commandlineSize = _appArgs.GetSize().value_or(emptySize);
proposedSize = TermControl::GetProposedDimensions(settings.DefaultSettings(),
dpi,
commandlineSize.width,
commandlineSize.height);
}

// GH#2061 - If the global setting "Always show tab bar" is
Expand Down Expand Up @@ -738,6 +743,12 @@ namespace winrt::TerminalApp::implementation
}
}

// Commandline args trump everything else
if (_appArgs.GetPosition().has_value())
{
initialPosition = _appArgs.GetPosition().value();
}

return {
initialPosition.X ? initialPosition.X.Value() : defaultInitialX,
initialPosition.Y ? initialPosition.Y.Value() : defaultInitialY
Expand Down
6 changes: 6 additions & 0 deletions src/cascadia/TerminalApp/Resources/en-US/Resources.resw
Expand Up @@ -394,6 +394,12 @@
<data name="CmdWindowTargetArgDesc" xml:space="preserve">
<value>Specify a terminal window to run the given commandline in. "0" always refers to the current window. </value>
</data>
<data name="CmdPositionDesc" xml:space="preserve">
<value>Specify the position for the terminal, in "x,y" format.</value>
</data>
<data name="CmdSizeDesc" xml:space="preserve">
<value>Specify the number of columns and rows for the terminal, in "c,r" format.</value>
</data>
<data name="NewTabSplitButton.[using:Windows.UI.Xaml.Automation]AutomationProperties.HelpText" xml:space="preserve">
<value>Press the button to open a new terminal tab with your default profile. Open the flyout to select which profile you want to open.</value>
</data>
Expand Down
17 changes: 14 additions & 3 deletions src/cascadia/TerminalControl/TermControl.cpp
Expand Up @@ -2032,15 +2032,26 @@ namespace winrt::Microsoft::Terminal::Control::implementation
// - dpi: The DPI we should create the terminal at. This affects things such
// as font size, scrollbar and other control scaling, etc. Make sure the
// caller knows what monitor the control is about to appear on.
// - commandlineCols: Number of cols specified on the commandline
// - commandlineRows: Number of rows specified on the commandline
// Return Value:
// - a size containing the requested dimensions in pixels.
winrt::Windows::Foundation::Size TermControl::GetProposedDimensions(const IControlSettings& settings, const uint32_t dpi)
winrt::Windows::Foundation::Size TermControl::GetProposedDimensions(const IControlSettings& settings,
const uint32_t dpi,
int32_t commandlineCols,
int32_t commandlineRows)
{
// If the settings have negative or zero row or column counts, ignore those counts.
// (The lower TerminalCore layer also has upper bounds as well, but at this layer
// we may eventually impose different ones depending on how many pixels we can address.)
const auto cols = ::base::saturated_cast<float>(std::max(settings.InitialCols(), 1));
const auto rows = ::base::saturated_cast<float>(std::max(settings.InitialRows(), 1));
const auto cols = ::base::saturated_cast<float>(std::max(commandlineCols > 0 ?
commandlineCols :
settings.InitialCols(),
1));
const auto rows = ::base::saturated_cast<float>(std::max(commandlineRows > 0 ?
commandlineRows :
settings.InitialRows(),
1));

const winrt::Windows::Foundation::Size initialSize{ cols, rows };

Expand Down
5 changes: 4 additions & 1 deletion src/cascadia/TerminalControl/TermControl.h
Expand Up @@ -114,7 +114,10 @@ namespace winrt::Microsoft::Terminal::Control::implementation
Windows::UI::Xaml::Automation::Peers::AutomationPeer OnCreateAutomationPeer();
const Windows::UI::Xaml::Thickness GetPadding();

static Windows::Foundation::Size GetProposedDimensions(const IControlSettings& settings, const uint32_t dpi);
static Windows::Foundation::Size GetProposedDimensions(const IControlSettings& settings,
const uint32_t dpi,
int32_t commandlineCols,
int32_t commandlineRows);
static Windows::Foundation::Size GetProposedDimensions(const IControlSettings& settings, const uint32_t dpi, const winrt::Windows::Foundation::Size& initialSizeInChars);

void BellLightOn();
Expand Down
5 changes: 4 additions & 1 deletion src/cascadia/TerminalControl/TermControl.idl
Expand Up @@ -21,7 +21,10 @@ namespace Microsoft.Terminal.Control
IControlAppearance unfocusedAppearance,
Microsoft.Terminal.TerminalConnection.ITerminalConnection connection);

static Windows.Foundation.Size GetProposedDimensions(IControlSettings settings, UInt32 dpi);
static Windows.Foundation.Size GetProposedDimensions(IControlSettings settings,
UInt32 dpi,
Int32 commandlineCols,
Int32 commandlineRows);

void UpdateControlSettings(IControlSettings settings);
void UpdateControlSettings(IControlSettings settings, IControlAppearance unfocusedAppearance);
Expand Down
Expand Up @@ -92,6 +92,7 @@
<ClInclude Include="VsDevShellGenerator.h" />
<ClInclude Include="VsSetupConfiguration.h" />
<ClInclude Include="WslDistroGenerator.h" />
<ClInclude Include="ModelSerializationHelpers.h" />
</ItemGroup>
<!-- ========================= Cpp Files ======================== -->
<ItemGroup>
Expand Down
82 changes: 82 additions & 0 deletions src/cascadia/TerminalSettingsModel/ModelSerializationHelpers.h
@@ -0,0 +1,82 @@
/*++
Copyright (c) Microsoft Corporation
Licensed under the MIT license.
Module Name:
- ModelSerializationHelpers.h
Abstract:
- Helper methods for serializing/de-serializing model data.
--*/

#pragma once

// Function Description:
// - Helper for converting a pair of comma separated, potentially absent integer values
// into the corresponding left and right values. The leftValue and rightValue functions
// will be called back with the associated parsed integer value, assuming it's present.
// (100, 100): leftValue and rightValue functions both called back with 100.
// (100, ), (100, abc): leftValue function called back with 100
// (, 100), (abc, 100): rightValue function called back with 100
// (,): no function called back
// (100, 100, 100): we only read the first two values, this is equivalent to (100, 100)
// Arguments:
// - string: The string to parse
// - leftValue: Function called back with the value before the comma
// - rightValue: Function called back with the value after the comma
_TIL_INLINEPREFIX void ParseCommaSeparatedPair(const std::string& string,
std::function<void(int32_t)> leftValue,
std::function<void(int32_t)> rightValue)
{
static constexpr auto singleCharDelim = ',';
std::stringstream tokenStream(string);
std::string token;
uint8_t index = 0;

// Get values till we run out of delimiter separated values in the stream
// or we hit max number of allowable values (= 2)
// Non-numeral values or empty string will be caught as exception and we do not assign them
for (; std::getline(tokenStream, token, singleCharDelim) && (index < 2); index++)
{
try
{
int32_t value = std::stol(token);
if (index == 0)
{
leftValue(value);
}

if (index == 1)
{
rightValue(value);
}
}
catch (...)
{
// Do nothing
}
}
}

// See: ParseCommaSeparatedPair
_TIL_INLINEPREFIX ::winrt::Microsoft::Terminal::Settings::Model::LaunchPosition LaunchPositionFromString(const std::string& string)
{
::winrt::Microsoft::Terminal::Settings::Model::LaunchPosition initialPosition;
ParseCommaSeparatedPair(
string,
[&initialPosition](int32_t left) { initialPosition.X = left; },
[&initialPosition](int32_t right) { initialPosition.Y = right; });
return initialPosition;
}

// See: ParseCommaSeparatedPair
_TIL_INLINEPREFIX ::til::size SizeFromString(const std::string& string)
{
til::size size{};
ParseCommaSeparatedPair(
string,
[&size](int32_t left) { size.width = left; },
[&size](int32_t right) { size.height = right; });
return size;
}
Expand Up @@ -17,6 +17,7 @@ Module Name:

#include "JsonUtils.h"
#include "SettingsTypes.h"
#include "ModelSerializationHelpers.h"

JSON_ENUM_MAPPER(::winrt::Microsoft::Terminal::Core::CursorStyle)
{
Expand Down Expand Up @@ -318,51 +319,12 @@ JSON_FLAG_MAPPER(::winrt::Microsoft::Terminal::Control::CopyFormat)
}
};

// Type Description:
// - Helper for converting the initial position string into
// 2 coordinate values. We allow users to only provide one coordinate,
// thus, we use comma as the separator:
// (100, 100): standard input string
// (, 100), (100, ): if a value is missing, we set this value as a default
// (,): both x and y are set to default
// (abc, 100): if a value is not valid, we treat it as default
// (100, 100, 100): we only read the first two values, this is equivalent to (100, 100)
template<>
struct ::Microsoft::Terminal::Settings::Model::JsonUtils::ConversionTrait<::winrt::Microsoft::Terminal::Settings::Model::LaunchPosition>
{
::winrt::Microsoft::Terminal::Settings::Model::LaunchPosition FromJson(const Json::Value& json)
{
::winrt::Microsoft::Terminal::Settings::Model::LaunchPosition ret;
auto initialPosition{ json.asString() };
static constexpr auto singleCharDelim = ',';
std::stringstream tokenStream(initialPosition);
std::string token;
uint8_t initialPosIndex = 0;

// Get initial position values till we run out of delimiter separated values in the stream
// or we hit max number of allowable values (= 2)
// Non-numeral values or empty string will be caught as exception and we do not assign them
for (; std::getline(tokenStream, token, singleCharDelim) && (initialPosIndex < 2); initialPosIndex++)
{
try
{
int64_t position = std::stol(token);
if (initialPosIndex == 0)
{
ret.X = position;
}

if (initialPosIndex == 1)
{
ret.Y = position;
}
}
catch (...)
{
// Do nothing
}
}
return ret;
return LaunchPositionFromString(json.asString());
}

bool CanConvert(const Json::Value& json)
Expand Down

0 comments on commit 43dbbd5

Please sign in to comment.